/*
    Amaster Version 3.10e
    (C) 1996-2003 Michal Korzycki and Piotr Winiarczyk
    VGA-Planets universe master program.

    Compile with pdk library.

    below v0.96 written by Michal Korzycki

    v0.98 Rewritten to C from C++

    v1.0  New config reader
          Near far check
          Natives cash check

    v1.1  Random seed control
          Homeworld search progress display

    v1.2  Wormhole generator
          Map generator and validator

    v2.0  Minerals check
          Portability

    v2.1  Near,Far search radius
          2 bugs fixed in config reader

    v2.2  Statistics, -t option

    v2.3  Freeships

    v2.4  Base Control
          AuxData saved

    v2.5  01.03.2001
          All tech levels on HW can be set
          Free ammo for free ships.

          02.2001
          Bugs found by Degi. PlanetsMinDistance was not read from config file.
          When AllPlanetsTheSame, Fed planets temperature was no set to 50

    v3.0  08.03.2001
          New HW finding algorithm, should be faster.

          10.03.2001
          Temperature 50 for all home planets if biosupport is on
          (natives friendly temperature).

    v3.1  21.03.2001
          Homeworld minerals density read from config.
          Improvment in statistic module.
          Parameters in config file for HW finding algoritm.
          Wormholes can be in same distance to homeworlds.
          No map generation progress info as default.

          23.03.2001
          Documentation update.
          Biosupport update.
          Natives post-master statistic.

          24.03.2001
          Some config file reader minor changes
          Compiles with no warrings on Linux (-Wall)

    v3.2  25.05.2001
          Changes in configuration parameters.
          PlanetSurfaceRanges, PlanetCoreRangesUsual and PlanetCoreRangesAlternate
          have 8 parameters: Nmin, Tmin, Dmin, Mmin, Nmax, Tmax, Dmax, Nmax

    v3.3  20.06.2001
          no free ammo for free ships without tubes/bays and max ammo is hullcargocapacity
          no waypoint for free ships
          'gobal' typing bug
          DOSWrite16 for map
          bugs when allplanetsthesame fixed
          config parameters range basic check, more errors info
          AllowWraparoundMap instead IsMapWraping
          New parameter WraparoundRectangle
          More statistic : climate, universe surface

    v3.4  10.07.2001
          new function doCheck()

          05.08.2001
          Same changes in default parameters: Planet1, Planet2, HomeworldSurfaceM
          MyRandomRange checked and fixed
          5 new parameters for wormhole generation procedure

    v3.5  06.08.2001
          Bio support has more options, changed BioSupport functions.
          Native population is truncated to fit planet population capacity.
          Fixed and improved temperature statistics.

          07.08.2001
          DesertCrystalHomeworld config parameter replaced by CrystalsPreferDeserts.
          Code and documentation improvement/cleaning.
          Letter for minor version changes.
          Total run time displayed.

          12.08.2001
    'd'   nextturn.hst bug fixed.

          13.08.2001
    'e'   fclose possible bug fixed.

    v3.6  31.08.2001
          Ion Storms for THost.

          08.10.2001
    'a'   Natives on HomePlanets are intact when Planet1=-1, etc

    'b'  '-n' switch, for showing players base and planets IDs

    'c'    OwnedBases can be set to 0

    v3.7   10.10.2001
           HomePlanet1,..,HomePlanet9 config parameters introduced.
           Homeplanets clans, mines, factories, defence, cash,
           supplies, colonist tax and happy can be set.

           Homeworld mines, factories, defence, supplies, colonist tax
           and happy config parameters.

    'a'    15.10.2001
           Changes in default parameters.
           Siliconoid prefer desert.
           Message to players.

   v3.8    14.11.2001
           Host can provide homeworlds IDs, as in pmaster.
           Up to 100 homeplanets can be set.

    'a'    15.11.2001
           Small correction in map creation.

    'b'    19.11.2001
           Bug in homeplanet procedure found.

    'c'    DeafultHomePlanet parameter.

           25.11.2001
    'd'    AllPlayerPlanetsTheSame parameter.
           Change in action of AllOwnedPlanetsTheSame.
           Change in homeplanet assigment algorithm.

    'e'    BaseFreeHulls, BaseFreeEnginess, BaseFreeBeams and
           BaseFreeTorps parameters instead of BaseFreeParts.

           04.02.2002
    'f'    PlayerRace, CrystalSinTempBehavior, ClimateLimitsPopulation,
           PlayerRace, MapTruehullByPlayerRace, MaxColTempSlope
           parameters are read from amaster.src.
           Having them, bugs fixed in free ships, and temperatures of
           Crystal/Tholian homeworlds. Small improvments in AdjustPopulations.
           More information in -v option.

           05.02.2002
    'g'    Since -O3 option in DJGPP GCC compiler is building exe file
           causing runtime errors same manual optimalization was made.
           Nearly 60% of Amaster run time was used to compute sqrt
           in PlanetDist and DistWrap procedures. So all calls to those
           procedures were changed to call PlanetDist2 and DistWrap2.
           Now they return square of distance. All 'if' statements where
           change to suit it. Program runs now about 75 % faster.

    'h'    12.02.2002
           Small correction to max natives number procedure.
           CrystalSinTempBehavior is not longer used.
           More information on reading config file.

    'i'    01.03.2002
           Bug in BaseFreeTorps loading.

    'j'    08.03.2002
           Bug in HomePlanetXX parameters corrected.
           NoAmorphousOnHomePlanets parameter.
           Program returns 0 on success exit.

    'k'    27.03.2002
           New option: HomeworldsRange, idea by Daniel Bruedigam.

    'l'    29.03.2002
           Bug in reading PlanetXX parameters corrected.

   v3.9    30.03.2002
           New format of PlanetXX parameters.
           New parameters DefaultNativesHappy and DefaultColonistHappy.

    'a'    17.04.2002
           "Movement" of starting bases. Base creation bug fixed.
           Bases have NoBaseMission on start. AdjustBasesTechs parameter.
           Natives on homeplanets fixed.

    'b'    18.04.2002
           Free ships on other bases too. FreeShipsOnBases.

    'c'    22.04.2002
           Same structular changes to program due to
           new BindPlanetsToBases parameter. Same bugfixes.

    'd'    24.04.2002
           PlanetsNumber parameter introduced.
           Small changes in post mastering statistics.

    'e'    07.05.2002
           FixMapChecksums parameter.
           Improvments in PlanetsNumber code.
           BaseHopsLimit now is 2 integer parameter.

           09.05.2002
           Small changes in messages displayed while running.

    'f'    09.05.2002
           New option -d shows number of created planets, bases, ships.
           Same small bugs fixed.

    'g'    27.05.2002
           Bugs introduced by PlanetsNumber parameter fixed.

    'h'    24.06.2002
           -g option - CountPlanets statistic procedure
           On planets with 0 or 100 temperature MaxNatives =0

    v3.10  05.07.2002
           New 32-bit random number generator.
           Test mode: -z -x -y options.
           While in test mode -i -t -g -n -d options does not work.
           Same of them will work in future.

           09.07.2002
           -p option can be set in test mode (-z).
           Number of succesfull and fail tests are shown.
           Same corrections in displaying test results done.
             Thanks to Maurits van Rees for those ideas.
           -o option for setting Homeworld in test mode
           Minor changes in config reader procedure.
           Changes in PlanetsStatistic procedure.

           10.07.2002
           -t, -g working in test mode

           11.07.2002
           Spelling bugs corrected.
           One can use -o option several times to provide more HWs IDs.

           12.07.2002
           Small improvments in test mode.

    'a'    13.07.2002
           Test mode can be run with map creating or ProvideHomeworlds=Yes

           19.07.2002
           Bugs correction in test mode.

           20.07.2002
           Speed improvment in test mode.
           PlanetDist2 is now macro using big 1M array, big speed improvment.

           21.07.2002
           Changes in fix xsum and ysum, no sum check in test mode.
           Faster map creation and verification.

    'b'    23.10.2002
           Creation of refdata.hst and xyplan.hst files for THost
           compatiblility.

    'c'    04.12.2002
           Bug fixes in various places.
           EXIT_SUCCESS on exit.
           Command line options processing improved.
           strncpy used in all cases.

           06.12.2002
           Code clean up.

           08.12.2002
           Small bug corrected when ProvideHomeworlds=Yes.
           
           05.01.2003
           More code clean up.

           13.01.2003
           Small bug fixed

           17.02.2003
           ProvideHomeworlds and PlanetsNumber != 500 and CreateMap=Yes bug fixed.
           Give warning when ProvideHomeworlds=Yes and CreateMap=Yes.
           
    'd'    2003.03.23 
           Compiled using gcc 3.2, linked with PDK 4.4.
           Small documentation update.
           
           2003.03.26
           Changed all '12' to RACE_NR+1
           Changed ShipCreate(i)
           Reading of pconfig.src.

    'e'    2003.10.27
           The number of planets for player can be 0.
           Code clearings.

           2003.10.28
           Bug in usage() corrected.
           Better handling of 0 planet for player.
           Bug in statistics corrected.

           2003.11.02
           1000 random configs test.
           Changed information displaying when problems
           with finding Homeworlds occurs.
           Bug in handling case when Homeworlds are not found.
           Bug in ship creations procedure.
           
    'f'    2003.11.16
           New invoke option -k file.pgm
           used to provide map creation mask PGM file.

           2003.11.18
           Debugging file mask code.
*/

#ifdef MSDOS
#include <conio.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <ctype.h>
#include "phostpdk.h"

#define  AND   &&
#define  OR    ||
#define  EQ    ==
#define  NEQ   !=
#define  GT    >
#define  GE    >=
#define  LT     <
#define  LE    =<

#define  MAXHOMETRY      5000
#define  MAXSHIPTRY     10000

#define  PARAM_NUMBER    137

#define  CONFIG_BOOL     0
#define  CONFIG_INT      1
#define  CONFIG_INT11_O  2
#define  CONFIG_BOOL11   3
#define  CONFIG_BOOL11_O 4
#define  CONFIG_INT4     5
#define  CONFIG_INT8     6
#define  CONFIG_INT9     7
#define  CONFIG_INT2     8
#define  CONFIG_INT11    9
#define  CONFIG_STRING   10

#define  MAX16          0x7FFFUL
#define  MAX32      0x7FFFFFFFUL

#define  MAXWORMHOLES   100
#define  MAXIONSTORMS   50
#define  MAXHOMEPLANETS 99

#define  STATS_NUMBER   50

#define  PlanetDist2(i,j) BigDistance[i][j]

#define PHOST3_SHIP_NR  500

/* version number and letter */
Uns16 pMajor=3;
Uns16 pMinor=10;
char  pLetter='f';

struct config_rec  {
              int     min,max;
              char    name[80];
              char    name_d[80];
              Uns16   mode;
              Boolean read;
                };

struct ionstorm {
                Uns16 x,y,r,v,head,mark;
               };


const char     *defaultpath = ".";

typedef Uns16   Rtable[RACE_NR+1];
typedef int     Itable[RACE_NR+1];
Rtable          Homeworlds = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

Uns16           Planets[RACE_NR+1][MAXHOMEPLANETS+1];
Uns16           Bases  [RACE_NR+1][MAXHOMEPLANETS+1];
Uns16           PlanetsRead[MAXHOMEPLANETS+1];
int             PlanetsNat[MAXHOMEPLANETS+1][5];

/* help variables for PlanetDist2 and DistWrap2 functions */
int             UNI_DX, UNI_DY;
Uns32           BigDistance[PLANET_NR+1][PLANET_NR+1];

/******************************************************/
struct config_rec config[PARAM_NUMBER] = {
   {    0,    0,"RaceIsPlaying"            ,"Yes" ,CONFIG_BOOL11_O,False},
   {    0,MAX16,"PlanetSurfaceRanges"      ,"0, 0, 0, 0, 250, 50, 40, 25" ,CONFIG_INT8,False},
   {    1,  100,"PlanetDensityRanges"      ,"10, 10, 10, 10, 100, 100, 100, 100" ,CONFIG_INT8,False},
   {    0,    0,"Password1"                ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password2"                ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password3"                ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password4"                ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password5"                ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password6"                ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password7"                ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password8"                ,"None" ,CONFIG_STRING,False},  /* 10 */
   {    0,    0,"Password9"                ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password10"               ,"None" ,CONFIG_STRING,False},
   {    0,    0,"Password11"               ,"None" ,CONFIG_STRING,False},
   {    0,  100,"PlanetCoreUsualFrequency" ,"65, 75, 85, 95",CONFIG_INT4,False},
   {    0,MAX16,"PlanetCoreRangesUsual"    ,"0, 0, 0, 0, 700, 500, 500, 200",CONFIG_INT8,False},
   {    0,MAX16,"PlanetCoreRangesAlternate","0, 0, 0, 0, 12000, 12000, 12000, 12000",CONFIG_INT8,False},
   {    0, 1000,"NativesOnPlanetFrequency" ,"60"   ,CONFIG_INT ,False},
   {    0, 1000,"NativeTypeFrequencies"    ,"50, 50, 50, 50, 100, 50, 50, 50, 50",CONFIG_INT9 ,False},
   {    0, 1000,"NativeGovFrequencies"     ,"25, 50, 50, 50, 75, 50, 50, 50, 25",CONFIG_INT9 ,False},
   {    0,160000UL,"NativeRange"           ,"250, 10000",CONFIG_INT2 ,False},  /* 20 */
   {    0,  100,"OwnedPlanets"             ,"1"  ,CONFIG_INT11_O,False},
   {    0,  100,"OwnedBases"               ,"1"  ,CONFIG_INT11_O,False},
   {    0,    0,"NoAmorphousOnHomePlanets" ,"No"  ,CONFIG_BOOL ,False},
   {    0,MAX16,"HomeworldsRange"          ,"1200,1200,2800,2800",CONFIG_INT4 ,2},
   {    0,  100,"DefaultNativesHappy"      ,"80"  ,CONFIG_INT ,False},  /* 25 */
   {    0,  100,"DefaultColonistHappy"     ,"80"  ,CONFIG_INT ,False},
   {    0,MAX16,"BaseHopsNumber"           ,"0"   ,CONFIG_INT ,False},
   {    0,MAX16,"BaseHopsFactor"           ,"100" ,CONFIG_INT ,False},
   {    0,    0,"FreeShipsOnBases"         ,"No"  ,CONFIG_BOOL11_O ,2},
   {    0,    0,"AdjustBasesTechs"         ,"Yes" ,CONFIG_BOOL ,False}, /* 30 */
   {    0,  100,"BaseHopsLimit"            ,"0,100"  ,CONFIG_INT2 ,False},
   {    0, 1000,"HomeworldsRadius"         ,"400"   ,CONFIG_INT     ,False},
   {    0,    0,"AllowWraparoundMap"       ,"Yes"   ,CONFIG_BOOL    ,False},
   {    0, 1000,"BorderWidth"              ,"0"     ,CONFIG_INT     ,False},
   {    0,100000UL,"HomeworldClans"        ,"30000" ,CONFIG_INT11_O ,False}, /* 35 */
   {    0,    0,"CrystalsPreferDeserts"   ,"Yes"   ,CONFIG_BOOL    ,False},
   {    0,MAX32,"HomeworldCash"            ,"15000" ,CONFIG_INT11_O ,False},
   {    0,MAX32,"HomeworldCoreN"           ,"4000"  ,CONFIG_INT11_O ,False},
   {    0,MAX32,"HomeworldCoreT"           ,"2000"  ,CONFIG_INT11_O ,False},
   {    0,MAX32,"HomeworldCoreD"           ,"3500"  ,CONFIG_INT11_O ,False}, /* 40 */
   {    0,MAX32,"HomeworldCoreM"           ,"1650"  ,CONFIG_INT11_O ,False},
   {    0,MAX16,"HomeworldSurfaceN"        ,"2000"  ,CONFIG_INT11_O ,False},
   {    0,MAX16,"HomeworldSurfaceT"        ,"300"   ,CONFIG_INT11_O ,False},
   {    0,MAX16,"HomeworldSurfaceD"        ,"350"   ,CONFIG_INT11_O ,False},
   {    0,MAX16,"HomeworldSurfaceM"        ,"150"   ,CONFIG_INT11_O ,False},
   {    1,   10,"StartingEngineTech"       ,"7"     ,CONFIG_INT11_O ,False},
   {    0,    0,"AllOwnedPlanetsTheSame"   ,"No"   ,CONFIG_BOOL ,False},
   {    0,    0,"BioSupport"               ,"Yes"   ,CONFIG_BOOL ,False},
   {    0,  100,"NearPlanetsNo"            ,"1,5"      ,CONFIG_INT2 ,2},
   {    0,MAX16,"MineTritanium"            ,"150,2000" ,CONFIG_INT2 ,2}, /* 50 */
   {    0,  100,"FarPlanetsNo"             ,"5,15"     ,CONFIG_INT2 ,2},
   {    0,MAX16,"MineDuranium"             ,"100,1500" ,CONFIG_INT2 ,2},
   {    0,    0,"NearFarPlanetCheck"       ,"Yes"   ,CONFIG_BOOL ,False},
   {    0,    0,"NativeCashCheck"          ,"Yes"   ,CONFIG_BOOL ,False},
   {    0,MAX16,"MaxPlanetCounter"         ,"100"    ,CONFIG_INT  ,False},
   {    0,MAX16,"NativeCash"               ,"1000,7000"    ,CONFIG_INT2 ,2},
   {    0,MAX16,"MineMolybdenium"          ,"50,1000"   ,CONFIG_INT2 ,2},
   {    0,MAX16,"NativeCashSearchRadius"   ,"165"   ,CONFIG_INT ,2},
   {    0,    0,"CreateWormholes"          ,"Yes"   ,CONFIG_BOOL ,False},
   {    0,MAXWORMHOLES,"WormholeNumber"    ,"25"    ,CONFIG_INT ,2},  /* 60 */
   {    0,  100,"WormholeUniDirChance"     ,"20"    ,CONFIG_INT ,2},
   {    0,  100,"WormholeStartMoveChance"  ,"20"    ,CONFIG_INT ,2},
   {    0,  100,"WormholeEndMoveChance"    ,"20"    ,CONFIG_INT ,2},
   {    0,MAX16,"WormholeStartRange"       ,"1000,1000,3000,3000" ,CONFIG_INT4 ,2},
   {    0,MAX16,"WormholeEndRange"         ,"1000,1000,3000,3000" ,CONFIG_INT4 ,2},
   {    0,  100,"WormholeInstabilityRange" ,"0,30"    ,CONFIG_INT2 ,2},
   {    0,MAX16,"WormholeMassRange"        ,"1,32000" ,CONFIG_INT2 ,2},
   {    0,    0,"CreateMap"                ,"Yes"     ,CONFIG_BOOL ,False},
   {    0, 1000,"PlanetsMinDistance"       ,"6"       ,CONFIG_INT  ,2},
   {    0,    0,"MineCheck"                ,"Yes"     ,CONFIG_BOOL ,False}, /* 70 */
   {    0, 1000,"MaxMapCounter"            ,"20"      ,CONFIG_INT  ,False},
   {    0, 1000,"MineSearchRadius"         ,"165"     ,CONFIG_INT  ,2},
   {    0,  100,"MaxMineTurns"             ,"20"      ,CONFIG_INT  ,2},
   {    0, 1000,"NearSearchRadius"         ,"84"      ,CONFIG_INT  ,2},
   {    0, 1000,"FarSearchRadius"          ,"165"     ,CONFIG_INT  ,2},
   {    0,    0,"FreeShips"                ,"No"      ,CONFIG_BOOL ,False},
   {    0,  500,"FreeShipsNumber"          ,"2"       ,CONFIG_INT11_O,2},
   {    0,    0,"FreeShipsAllTheSame"      ,"Yes"     ,CONFIG_BOOL ,2},
   {    1,  105,"FreeShipsHull"            ,"17"      ,CONFIG_INT  ,2},
   {    1,    9,"FreeShipsEngines"         ,"6"       ,CONFIG_INT  ,2},  /* 80 */
   {    1,   10,"FreeShipsBeams"           ,"6"       ,CONFIG_INT  ,2},
   {    1,   10,"FreeShipsTubes"           ,"6"       ,CONFIG_INT  ,2},
   {    0,  200,"BaseFreeDefence"          ,"10"      ,CONFIG_INT11_O ,False},
   {    0,   60,"BaseFreeFighters"         ,"20"      ,CONFIG_INT11_O ,False},
   {    0,    0,"BaseFreeHulls"            ,"Yes"     ,CONFIG_BOOL11_O ,False},
   {    0,    0,"AllBasesTheSame"          ,"No"      ,CONFIG_BOOL ,False},
   {    1,   10,"StartingHullTech"         ,"1"       ,CONFIG_INT11_O ,False},
   {    1,   10,"StartingBeamTech"         ,"1"       ,CONFIG_INT11_O ,False},
   {    1,   10,"StartingTubeTech"         ,"1"       ,CONFIG_INT11_O ,False},
   {    0,MAX16,"FreeShipsAmmo"            ,"20"      ,CONFIG_INT  ,2},          /* 90 */
   {    0,  100,"HomeworldDensityN"        ,"20"      ,CONFIG_INT11_O ,False},
   {    0,  100,"HomeworldDensityT"        ,"20"      ,CONFIG_INT11_O ,False},
   {    0,  100,"HomeworldDensityD"        ,"15"      ,CONFIG_INT11_O ,False},
   {    0,  100,"HomeworldDensityM"        ,"95"      ,CONFIG_INT11_O ,False},
   {    0,MAX32,"MaxHWCounter"             ,"50000"   ,CONFIG_INT  ,False},       /* 95 */
   {    0,    0,"NoWormholesNearHomeworlds","Yes"     ,CONFIG_BOOL ,2},
   {    0, 1000,"MinWormHomeDistance"      ,"100"     ,CONFIG_INT  ,2},
   {    0,MAX16,"WraparoundRectangle"      ,"1000,1000,3000,3000" ,CONFIG_INT4 ,False},
   {    0,    0,"NoWormholesNearPlanets"   ,"Yes"     ,CONFIG_BOOL ,2},
   {    0, 1000,"MinWormPlanetDistance"    ,"10"      ,CONFIG_INT  ,2},      /* 100 */
   {    0, 1000,"MinWormholesDistance"     ,"50"      ,CONFIG_INT  ,2},
   {    0,MAX32,"MaxWormholesCounter"      ,"10000"   ,CONFIG_INT  ,2},
   {    0, 1000,"MinWormholeLength"        ,"50"      ,CONFIG_INT  ,2},
   {    0,  100,"BioSupportLevel"          ,"50"      ,CONFIG_INT  ,2},
   {    0,  100,"PlanetsTempRange"         ,"0,100"   ,CONFIG_INT2 ,2},    /* 105 */
   {    0,  100,"OwnedPlanetsTempRange"    ,"15,84"   ,CONFIG_INT2 ,2},
   {    0,    0,"AdjustPopulations"        ,"Yes"     ,CONFIG_BOOL ,False},
   {    0,    0,"CreateIonStorms"          ,"No"      ,CONFIG_BOOL ,False},
   {    0, 1000,"IonStormsVoltageRange"    ,"1,100"   ,CONFIG_INT2 ,2},
   {    0,  500,"IonStormsRadiusRange"     ,"10,150"  ,CONFIG_INT2 ,2},    /* 110 */
   {    1,   50,"IonStormsNumber"          ,"5"       ,CONFIG_INT  ,2},
   {    0,    0,"NoIonStormsNearHomeworlds","Yes"     ,CONFIG_BOOL ,2},
   {    0, 1000,"MinIonStormsHomeDistance" ,"150"     ,CONFIG_INT  ,2},
   {    0,MAX16,"IonStormsCenterRange","1000,1000,3000,3000",CONFIG_INT4,2},
   {    0,MAX16,"DefaultHomePlanet" ,"1000,10,100,5,0,0,80,6" ,CONFIG_INT8 ,True}, /* 115 */
   {    0,0    ,"AllPlayerPlanetsTheSame"  ,"No"      ,CONFIG_BOOL ,False},
   {    0,    0,"BaseFreeEngines"          ,"Yes"     ,CONFIG_BOOL11_O ,False},
   {    0,    0,"BaseFreeBeams"            ,"Yes"     ,CONFIG_BOOL11_O ,False},
   {    0,    0,"BaseFreeTorps"            ,"Yes"     ,CONFIG_BOOL11_O ,False},
   {    1,   11,"PlayerRace"               ,"1,2,3,4,5,6,7,8,9,10,11",CONFIG_INT11,False},  /* 120 */
   {    0,    0,"MapTruehullByPlayerRace"  ,"Yes"     ,CONFIG_BOOL,False},
   {    0,    0,"CrystalSinTempBehavior"   ,"No"      ,CONFIG_BOOL,False},
   {    0,    0,"ClimateLimitsPopulation"  ,"Yes"     ,CONFIG_BOOL,False},
   {    0,MAX32,"HomeworldMines"            ,"100"    ,CONFIG_INT11_O ,False},
   {    0,MAX32,"HomeworldFactories"        ,"150"    ,CONFIG_INT11_O ,False}, /* 125 */
   {    0,MAX32,"HomeworldDefence"          ,"100"    ,CONFIG_INT11_O ,False},
   {    0,MAX32,"HomeworldSupplies"         ,"1000"   ,CONFIG_INT11_O ,False},
   {    0,MAX32,"HomeworldColonistTax"      ,"6"      ,CONFIG_INT11_O ,False},
   {    0,MAX32,"HomeworldColonistHappy"    ,"80"     ,CONFIG_INT11_O ,False},
   {    0,    0,"ProvideHomeworlds"         ,"No"     ,CONFIG_BOOL    ,False}, /* 130 */
   {    0,  500,"Homeworlds"                ,"1,2,3,4,5,6,7,8,9,10,11",CONFIG_INT11 ,False},
   {    0,MAX16,"MaxColTempSlope"           ,"1000"   ,CONFIG_INT  ,False},
   {    0,    0,"BindPlanetsToBases"        ,"Yes"    ,CONFIG_BOOL ,False},
   {    1,PLANET_NR,"PlanetsNumber"         ,"500"    ,CONFIG_INT  ,2},
   {    0,    0,"FixMapChecksums"           ,"Yes"    ,CONFIG_BOOL ,2},  /* 135 */
   {    0, 2000,"HomeworldsMaxRadius"      ,"600"   ,CONFIG_INT     ,False},
   };


/******************************************************/
/* Default Settings */
Rtable    RaceIsPlaying    = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Rtable    PlayerRace       = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
Uns16     MapTruehullByPlayerRace = True;
Uns16     CrystalsPreferDeserts   = True;
Uns16     CrystalSinTempBehavior  = False;
Uns16     ClimateLimitsPopulation = True;
Uns16     MaxColTempSlope         = 1000;
Uns16     AllowWraparoundMap      = True;
Uns16     WraparoundRectangle[4]  = { 1000,1000,3000,3000 };

Uns16     PlanetSurfaceRanges[8] = {0, 0, 0, 0, 250, 50, 40, 25};
Uns16     PlanetDensityRanges[8] = {10, 10, 10, 10, 100, 100, 100, 100};

char      Password1[11]  = "none";
char      Password2[11]  = "none";
char      Password3[11]  = "none";
char      Password4[11]  = "none";
char      Password5[11]  = "none";
char      Password6[11]  = "none";
char      Password7[11]  = "none";
char      Password8[11]  = "none";
char      Password9[11]  = "none";
char      Password10[11] = "none";
char      Password11[11] = "none";

Uns16     PlanetCoreUsualFrequency[4]  = {65, 75, 85, 95};
Uns16     PlanetCoreRangesUsual[8]     = {0, 0, 0, 0, 700, 500, 500, 200};
Uns16     PlanetCoreRangesAlternate[8] = {0, 0, 0, 0, 12000, 12000, 12000, 12000};
Uns16     NativesOnPlanetFrequency     = 60;
Uns16     NativeTypeFrequencies[10]    = {0, 50, 50, 50, 50, 100, 50, 50, 50, 50};
Uns16     NativeGovFrequencies[10]     = {0, 25, 50, 50, 50, 75, 50, 50, 50, 25};
Uns16     NativeRange[2]   = {250, 10000};
Uns16     DefaultNativesHappy          = 80;
Uns16     DefaultColonistHappy         = 80;

Rtable    OwnedPlanets     = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Rtable    OwnedBases       = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

Uns16    HomePlanet[100][8] ;
Uns16    DefaultHomePlanet[8] = { 1000,10,100,5,0,0,80,6 };
Uns16    NoAmorphousOnHomePlanets = 0;

Uns16     HomeworldsRadius       = 400;
Uns16     HomeworldsMaxRadius    = 600;
Uns16     HomeworldsRange[4]     = { 1200,1200,2800,2800 };
Uns16     ProvideHomeworlds      = False;
Rtable    Homeworlds_            = { 0,1,2,3,4,5,6,7,8,9,10,11 };
Uns16     BorderWidth            = 0;
Rtable    HomeworldClans = {0, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000};
Rtable    HomeworldCash = {0, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000};
Rtable    HomeworldCoreN = {0, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000};
Rtable    HomeworldCoreT = {0, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000};
Rtable    HomeworldCoreD = {0, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500, 3500};
Rtable    HomeworldCoreM = {0, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650, 1650};
Rtable    HomeworldDensityN  = {0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 };
Rtable    HomeworldDensityT  = {0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 };
Rtable    HomeworldDensityD  = {0, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 };
Rtable    HomeworldDensityM  = {0, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95 };
Rtable    HomeworldSurfaceN  = {0, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000};
Rtable    HomeworldSurfaceT  = {0, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300};
Rtable    HomeworldSurfaceD  = {0, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350};
Rtable    HomeworldSurfaceM  = {0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150};
Rtable    HomeworldMines     = {0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100};
Rtable    HomeworldFactories = {0, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150};
Rtable    HomeworldDefence   = {0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100};
Rtable    HomeworldSupplies  = {0, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000};
Rtable    HomeworldColonistTax   =  {0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6};
Rtable    HomeworldColonistHappy =  {0, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80};

Rtable    StartingEngineTech = {0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
Rtable    StartingHullTech   = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Rtable    StartingBeamTech   = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Rtable    StartingTubeTech   = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Uns16     AllOwnedPlanetsTheSame   = False;
Uns16     AllPlayerPlanetsTheSame  = False;
Uns16     BioSupport               = True;
Uns16     BioSupportLevel          = 50;
Uns16     PlanetsTempRange[2]      = { 0,100 };
Uns16     OwnedPlanetsTempRange[2] = { 15, 84 };
Uns16     AdjustPopulations        = True;

Rtable    BaseFreeDefence      = {0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10};
Rtable    BaseFreeFighters     = {0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
Rtable    BaseFreeHulls        = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Rtable    BaseFreeEngines      = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Rtable    BaseFreeBeams        = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Rtable    BaseFreeTorps        = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
Uns16     AllBasesTheSame      = False;
Uns16     AdjustBasesTechs     = True;
Uns16     BaseHopsNumber       = 0;
Uns16     BaseHopsFactor       = 100;
Uns16     BaseHopsLimit[2]     = { 0, 100 };
Uns16     BindPlanetsToBases   = True;

Uns16     FreeShips            = False;
Rtable    FreeShipsOnBases     = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Rtable    FreeShipsNumber      = {0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2};
Uns16     FreeShipsAllTheSame  = False;
Uns16     FreeShipsHull        = 17;
Uns16     FreeShipsEngines     = 6;
Uns16     FreeShipsBeams       = 6;
Uns16     FreeShipsTubes       = 6;
Uns16     FreeShipsAmmo        = 20;

Uns16     NearFarPlanetCheck   = True;
Uns16     NearPlanetsNo[2]     = { 1, 5 };
Uns16     FarPlanetsNo[2]      = { 5, 15 };
Uns16     NearSearchRadius     = 84;
Uns16     FarSearchRadius      = 165;

Uns16     MineCheck            = True;
Uns16     MineTritanium[2]     = { 150, 2000 };
Uns16     MineDuranium[2]      = { 100, 1500 };
Uns16     MineMolybdenium[2]   = { 50, 1000 };
Rtable    RaceMiningRate       = { 0,100,100,100,100,100,100,100,100,100,100,100 };
Uns16     MineSearchRadius     = 165;

Uns16     NativeCashCheck   = True;
Rtable    NativeTaxRate     = {0,100,100,100,100,100,100,100,100,100,100,100 };
Uns32     NativeCash[2]     = { 1000, 7000 };
Uns16     NativeCashSearchRadius = 165;
Uns16     MaxMineTurns           = 20;

Uns16     CreateWormholes             = True;
Uns16     WormholeNumber              = 25;
Uns16     NoWormholesNearHomeworlds   = True;
Uns16     MinWormHomeDistance         = 100;

Uns16     NoWormholesNearPlanets      = True;
Uns16     MinWormPlanetDistance       = 10;
Uns16     MinWormholesDistance        = 50;
Uns32     MaxWormholesCounter         = 10000;
Uns16     MinWormholeLength           = 50;

Uns16     WormholeUniDirChance        = 20;
Uns16     WormholeStartMoveChance     = 20;
Uns16     WormholeEndMoveChance       = 20;
Uns16     WormholeStartRange[4]       = { 1000, 1000, 3000, 3000 };
Uns16     WormholeEndRange[4]         = { 1000, 1000, 3000, 3000 };
Uns16     WormholeInstabilityRange[2] = { 0, 30 };
Uns16     WormholeMassRange[2]        = { 1, 32000 };

Uns16     CreateIonStorms             = False;
Uns16     IonStormsVoltageRange[2]    = { 1,100 };
Uns16     IonStormsRadiusRange[2]     = { 10,150 };
Uns16     IonStormsNumber             = 5;
Uns16     NoIonStormsNearHomeworlds   = True;
Uns16     MinIonStormsHomeDistance    = 150;
Uns16     IonStormsCenterRange[4]     = { 1000,1000,3000,3000 };

Uns16     CreateMap                   = True;
Uns16     PlanetsMinDistance          = 6;
Uns16     PlanetsNumber               = 500;
Uns16     FixMapChecksums             = True;

Uns32     MaxMapCounter    = 20;
Uns32     MaxPlanetCounter = 100;
Uns32     MaxHWCounter     = 50000;

/*************************************************************/

static void     doPlanetRandomize(void);
static void     searchPlanetsBases(void);
static void     doHomePlanets(void);
static void     doHomeworlds(void);
static void     doWormhole(void);
static void     doCheck(void);
static void     doMap(void);
static void     doBases(void);
static void     doShips(void);
static void     doGrey(void);
static void     doRefData(void);

int          PlanetDistance(Uns16,Uns16);
int          DistWrap2(int,int,int,int);
double          min(double v1, double v2);
double          max(double v1, double v2);
void            ReadConfig(void);
void            ConOut(char *);
char            *strupr(char *);
Boolean         SearchHomeworlds(void);
void            PlanetStatistics(double table[]);
void            ShowPlanetStatistics(double table[]);
void            CountPlanets(double table[]);
void            ShowCountPlanets(double table[]);
static char    *NativesString(Uns16);
static char    *NativesGovmString(Uns16);
static char    *ClimateString(Uns16);
void ShowPlayersPIDs(void);
void ShowPlayersInfo(void);
void ShowHomeInfo(void);
Uns32 MaxNativesOnPlanet(Uns16,Uns16);
Uns32 GetOutsideWrapX(void);
Uns32 GetOutsideWrapY(void);

long MyGetRandomSeed(void);
void MySetRandomSeed(long seed);
long MyRandomRange(long Range);
void CheckForErrorsInConfig(void);
void TryReadPConfig(void);
unsigned char *LoadPGMFile(char *fileName);

/*************************************************************/

char configname[200]        ="amaster.src";
char logname[200]           ="amaster.log";
char wormholename[200]      ="wormhole.txt";
char mapfilename[200]       ="xyplan.dat";
char THostmapfilename[200]  ="xyplan.hst";
char PGMMaskFile[200];

Boolean UsePGMMaskFile = False;
Boolean printO      = False;
Boolean logF        = True;
Boolean HomeInfo    = False;
Boolean ProvideRandomSeed   = False;
Boolean WormGen     = True;
Boolean CreateXYMap = True;
Boolean Statistics  = False;
Boolean Algorithm   = False;
Boolean ShowTTime   = True;
Boolean ShowIDs     = False;
Boolean ShowNumbers = False;
Boolean WriteMess   = True;
Boolean FixMapSums  = True;
Boolean TestMode    = False;
Boolean PHost4Support = True;

Uns32 PGMFileX;
Uns32 PGMFileY;
Uns32 PGMFileD;
unsigned char *PGMFile;
Uns32 InputRandomSeed;
Uns32 TestModeNumber  = 50;
Uns32 TestModeDisplay = 20;
Uns32 TestModeHome[10]  = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Uns32 TestModeHomeNumber =0;
/* map creation progress info not displayed as default */
Boolean HomeProg    = False;

Uns16 GlobalNear    [PLANET_NR+1];
Uns16 GlobalFar     [PLANET_NR+1];
Uns16 GlobalNatCash [PLANET_NR+1];
Uns16 GlobalMineT   [PLANET_NR+1];
Uns16 GlobalMineD   [PLANET_NR+1];
Uns16 GlobalMineM   [PLANET_NR+1];
Boolean XYCanBeHW   [PLANET_NR+1];
Boolean XYisPlanet  [PLANET_NR+1];
Boolean CanBeHW     [PLANET_NR+1];

Boolean ConfigError;

Uns16 MaxShips;

static void
version(void)
{
  Info( "AMASTER - VGA-Planets Addle Scenario Master v%u.%u%c",pMajor, pMinor, pLetter);
}

static void
usage(void)
{
   Info("Usage: amaster [options] [GameDirectory [RootDirectory]]");
   Info("options:");
   Info(" -h        -- Print help and exit.");
   Info(" -v        -- Print version and exit.");
   Info(" -c        -- Print command line strings.");
   Info(" -l        -- Don't create log file.");
   Info(" -w        -- Don't create wormholes.");
   Info(" -m        -- Don't create map.");
   Info(" -u        -- Don't fix map checksums.");
#ifdef MSDOS
   Info(" -p        -- Show progress in map creation and validation or in test mode.");
#endif
   Info(" -i        -- Display homeworld near-far planets, native cash or minerals info.");
   Info(" -t        -- Display post mastering statistics.");
   Info(" -g        -- Display Homeworlds finding algorithm statistics.");
   Info(" -n        -- Display each player planet(s) IDs.");
   Info(" -d        -- Display each player planets, bases and ships number.");
   Info(" -r        -- Don't show total run time.");
   Info(" -a        -- Don't write message to players.");
   Info(" -s seed   -- Use seed in random generator.");
   Info(" -f name   -- Use file name as config file.");
   Info(" -z        -- Test mode ON. Tests provided map or configuration.");
   Info(" -y number -- Number of tests in test mode. Default is 50.");
   Info(" -x number -- Number of planets displayed in test mode summary. Default is 20.");
   Info(" -o ID     -- ID of one of the Homeworlds in test mode.");
   Info(" -3        -- PHOST3 support. Create universe for PHOST3 game.");
   Info(" -k name.pgm -- Use name.pgm file as map creation mask.");
}

void OptionError(char *option, char *value)
{
  ErrorExit("Value \"%s\" is not valid for option \"%s\"",value,option);
}


static void processOptions(int argc, char *argv[])
{
    int c;
    char tempbuf[100];
    int tempvalue, scaned;

    while ((c=pgetopt(argc, argv, "3hHvf:iclps:wmtrnaudgzx:y:o:k:")) NEQ EOF) {
                switch (c) {
                 case 'h': case 'H': default:
                        usage();
                        exit(EXIT_SUCCESS);
                 case 'v':
                        Info("PHOST Development Kit Version %u.%u",PDK_VERSION_MAJOR, PDK_VERSION_MINOR);
                        Info("Copyright (C) 1995-2003 Portable Host Project\n");
                        version();
                        Info("Copyright (C) 1996-2003 Michal Korzycki and Piotr Winiarczyk\n");
                        Info("GCC version: %s",__VERSION__);
                        Info("Compilation date & time: %s %s",__DATE__,__TIME__);
                        exit(EXIT_SUCCESS);
                 case 'c':
                        printO=True;
                        break;
                 case 'l':
                        logF=False;
                        break;
                 case 'r':
                        ShowTTime=False;
                        break;
                 case 'n':
                        ShowIDs=True;
                        break;
                 case 'd':
                        ShowNumbers=True;
                        break;
                 case 'a':
                        WriteMess=False;
                        break;
                 case 'i':
                        HomeInfo=True;
                        break;
                 case 'p':
                        HomeProg=True;
                        break;
                 case 'w':
                        WormGen=False;
                        break;
                 case 'm':
                        CreateXYMap=False;
                        break;
                 case 'u':
                        FixMapSums=False;
                        break;
                 case 't':
                        Statistics=True;
                        break;
                 case 'g':
                        Algorithm=True;
                        break;
                 case 'f':
                        strncpy(configname,poptarg,199);
                        break;
                 case 's':
                        strncpy(tempbuf,poptarg,99);
                        scaned=sscanf(tempbuf,"%d",&tempvalue);
                        if (scaned==1)
                        {
                          ProvideRandomSeed = True;
                          InputRandomSeed   = tempvalue;
                        }
                        else
                         OptionError("-s",tempbuf);
                        break;
                 case 'z':
                        TestMode=True;
                        break;
                 case 'y':
                        strncpy(tempbuf,poptarg,99);
                        scaned=sscanf(tempbuf,"%d",&tempvalue);
                        if (scaned==1)
                        {
                        TestModeNumber  = tempvalue;
                        }
                        else
                         OptionError("-y",tempbuf);
                        break;
                 case 'x':
                        strncpy(tempbuf,poptarg,99);
                        scaned=sscanf(tempbuf,"%d",&tempvalue);
                        if (scaned==1)
                        {
                        TestModeDisplay  = tempvalue;
                        }
                        else
                         OptionError("-x",tempbuf);
                        break;
                 case 'o':
                        if (TestModeHomeNumber<10)
                        {
                        strncpy(tempbuf,poptarg,99);
                        scaned=sscanf(tempbuf,"%d",&tempvalue);
                        if (scaned==1)
                        {
                          TestModeHome[TestModeHomeNumber]  = tempvalue;
                          TestModeHomeNumber++;
                        }
                        else
                         OptionError("-o",tempbuf);
                        }
                        else
                          ErrorExit("Too many arguments in -o option.");
                        break;
                 case '3':
                        PHost4Support = False;
                        setenv("PHOST_VERSION", "3", 1);
                        break;
                 case 'k':
                        strncpy(PGMMaskFile,poptarg,199);
                        UsePGMMaskFile = True;
                        break;
                }
        }

    if (poptind < argc) {
        gGameDirectory = argv[poptind++];
        }

    if (poptind < argc) {
        gRootDirectory = argv[poptind++];
        }

    if (poptind < argc) {
                         ErrorExit("Too many arguments. Invalid argument #%d - \"%s\"",poptind,argv[poptind]);
                        }

}

void printOptions(int argc, char *argv[])
{
  int i;

  Info("Command line strings :");
  for (i=0;i<argc;i++) Info("%s",argv[i]);
  Info("");
}

int  main(int argc, char *argv[])
{
     FILE *f;

     int i,j,k,HW,RiG;
     Uns32 pom,pom1;
     Uns32 RandSeed;
     Uns32 MapCounter;
     Uns32 PlanetCounter;

     Uns32 TestHome[PLANET_NR+1];
     Uns32 BestHome[PLANET_NR+1];
     Uns32 LocalTestNumber;

     Uns32 NatCash[RACE_NR+1];
     Uns16 MineT;
     Uns16 MineD;
     Uns16 MineM;

     Uns32 PlanetRestart, HomeRestart, MapRestart;

     char  tmp1[200],tmp2[200];

     time_t s_time, e_time;
     int sec_time,min_time;

     Boolean HWOk,TestGoGo,TestGo,TestCanCopy,ShowWait;
     Uns32  TestFail,Full,StatCounter,PCounter,TestType;
     
     double Stats[STATS_NUMBER];
     double TestStats[STATS_NUMBER];
     double PCounts[6];
     double TestPCounts[6];

/* Clear arrays */

     for(j=0;j<MAXHOMEPLANETS+1;j++)
        PlanetsRead[j]=0;

     for(i=0;i<5;i++)
       for(j=0;j<MAXHOMEPLANETS+1;j++)
     PlanetsNat[j][i]=-2;

     for(i=1;i<=RACE_NR;i++)
       for(j=0;j<MAXHOMEPLANETS+1;j++)
       {
         Planets[i][j]=0;
         Bases[i][j]=0;
       }
     PlanetRestart =0;
     HomeRestart   =0;
     MapRestart    =0;

     ShowWait = False;
     HWOk     = False;
     
     gRootDirectory = defaultpath;
     gGameDirectory = defaultpath;

     processOptions(argc, argv);
     if (logF==True)
     {
      gLogFile=OpenOutputFile(logname,GAME_DIR_ONLY|TEXT_MODE);
      if (gLogFile==NULL)
      {
         ErrorExit("Cannot open log file %s. Exiting.\n",logname);
      }
     }

 /* Initialize the PDK */
     InitPHOSTLib();
     version();
     Info("");

     if (printO==True) printOptions(argc, argv);

     if (PHost4Support)
     {
       Info("Create universe for PHOST4 game...");
       setenv("PHOST_VERSION", "4", 1);
     }
     else
       Info("Create universe for PHOST3 game...");

     MaxShips = 500;

     TryReadPConfig();
     Info("Reading file : %s, section : %%AMASTER",configname);
     ReadConfig();

     CheckForErrorsInConfig();

     if (UsePGMMaskFile) {
        Info("Reading map mask file : %s",PGMMaskFile);
        PGMFile=LoadPGMFile(PGMMaskFile);
     }

     for(j=0;j<MAXHOMEPLANETS+1;j++)
     if (PlanetsRead[j]==0)
     {
       HomePlanet[j][0]= DefaultHomePlanet[0];
       HomePlanet[j][1]= DefaultHomePlanet[1];
       HomePlanet[j][2]= DefaultHomePlanet[2];
       HomePlanet[j][3]= DefaultHomePlanet[3];
       HomePlanet[j][4]= DefaultHomePlanet[4];
       HomePlanet[j][5]= DefaultHomePlanet[5];
       HomePlanet[j][6]= DefaultHomePlanet[6];
       HomePlanet[j][7]= DefaultHomePlanet[7];
     }

/*   Set help variables*/
     UNI_DX= BorderWidth+(WraparoundRectangle[2]-WraparoundRectangle[0]);
     UNI_DY= BorderWidth+(WraparoundRectangle[3]-WraparoundRectangle[1]);

 /* Set a random seed based on the number of seconds since Jan. 1, 1970
    just so we don't get the same universe every time. */

     if (ProvideRandomSeed)
       RandSeed=InputRandomSeed;
     else
       RandSeed=MyGetRandomSeed();
     MySetRandomSeed(RandSeed);
     Info("Random seed is %ld",RandSeed);

     time(&s_time);
     MapCounter=0;

     RiG=0;
     for (i=1;i<=RACE_NR;i++)
      if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0)) RiG++;

 /* Same checking when test mode is ON */
     TestGoGo=True;
     if (TestMode)
     {
       TestType=1;
       if (ProvideHomeworlds)
         TestType=2;

       if (CreateMap&&CreateXYMap)
         TestType=2;

       if (TestType==2)
       {
        if ((!Statistics)&&(!Algorithm))
         {
         Error    ("When map is created or ProvideHomeworlds=Yes");
         ErrorExit("-t or -g option must be set.");
         }
       if (TestModeHomeNumber)
       {
         Warning("When map is created or ProvideHomeworlds=Yes");
         Warning("-o option will not work.");
       }
       }
       for(j=1;j<=PLANET_NR;j++)
          {
            TestHome[j]=0;
            BestHome[j]=j;
          }
       LocalTestNumber=0;
       TestFail=0;
       Full=0;
       StatCounter=0;
       PCounter=0;
       for(j=0;j<STATS_NUMBER;j++)
        TestStats[j]=0.0;
       for(j=0;j<6;j++)
        TestPCounts[j]=0.0;
        
       Info("Test Mode");
       if (TestModeNumber<1)
         ErrorExit("Invalid Test Mode number (-y option). ");
       if (TestModeDisplay>PLANET_NR)
         ErrorExit("Invalid Test Mode results display number (-x option). ");

       for(j=0;j<(int)TestModeHomeNumber;j++)
       if ((TestModeHome[j]<1)||(TestModeHome[j]>PLANET_NR))
         ErrorExit("Invalid Test Mode Homeworld ID (-o option). ");

       if (CreateMap&&CreateXYMap)
          Info("Testing %d maps. Please wait.",TestModeNumber);
       else
          Info("Testing map %d times. Please be patient.",TestModeNumber);
       
       if ((TestModeHomeNumber)&&(TestType==1))
       {
       tmp1[0]=0;
       for(j=0;j<(int)TestModeHomeNumber;j++)
       {
         sprintf(tmp2,"ID %ld%s",TestModeHome[j],(j!=(int)TestModeHomeNumber-1?", ":""));
         strcat(tmp1,tmp2);
       }
      strcat(tmp1,(j==1?" is ":" are "));
       
       Info("Searching for cases when planet%s %sHomeworld%s.",
       (j==1?"":"s"),tmp1,(j==1?"":"s"));
       }
     }

     while (TestGoGo)
     {
     while (MapCounter<MaxMapCounter)
     {
     TestGo=True;

     for (i=1;i<=PLANET_NR;i++)
         XYCanBeHW[i]=True;

     if (CreateMap&&CreateXYMap)
     {
     MapRestart++;

     if ((!TestMode)&&(MapRestart==1)) Info("Initializing Map...");
     doMap();
     }
     MapCounter++;
     if (!ReadGlobalData())
         ErrorExit("Cannot read global data.");
     doCheck();

     if (!ProvideHomeworlds)
     {
 /* If !AllowWraparoundMap filter planets near border when needed */
     if ( ! AllowWraparoundMap)
     {
       for (i = 1; i <= PLANET_NR; i++)
        if (XYisPlanet[i])
        if ((PlanetLocationX(i)<HomeworldsRange[0])||
            (PlanetLocationX(i)>HomeworldsRange[2])||
            (PlanetLocationY(i)<HomeworldsRange[1])||
            (PlanetLocationY(i)>HomeworldsRange[3]))  XYCanBeHW[i]=False;
     }

/* If near far conditions are set, delete not usable planets as HW */
     if (NearFarPlanetCheck)
     {
     for (i=1;i<=PLANET_NR;i++)
        if (XYisPlanet[i])
         {
            if ((GlobalNear[i]>NearPlanetsNo[1])||(GlobalNear[i]<NearPlanetsNo[0])) XYCanBeHW[i]=False;
            if ((GlobalFar[i] > FarPlanetsNo[1])||(GlobalFar[i] < FarPlanetsNo[0])) XYCanBeHW[i]=False;
         }
     }

     HW=0;
     for (i=1;i<=PLANET_NR;i++)
        if (XYisPlanet[i])
          if (XYCanBeHW[i]) HW++;

     } /* ProvideHomeworlds=True */
     else
     HW=PlanetsNumber;

 /* These are the files we must create:
  PDATA.HST SHIP.HST BDATA.HST MINES.HST NEXTTURN.HST GEN.HST */

     if (HW>=RiG)
     {

     InitializeShips();
     InitializeBases();
     InitializeMines();
     InitializeHostGen();

     while (TestGo)
     {
     PlanetCounter=0;

     while (PlanetCounter<MaxPlanetCounter)
     {
     PlanetRestart++;

     if ((!TestMode)&&(PlanetRestart==1)) Info("Initializing Planets...");
     if ((!TestMode)&&(PlanetRestart==2)&&(!ShowWait)) { Info("Please wait..."); ShowWait=True;}

 /* Now, put some random minerals on planets, add natives, set temperature, etc. */
     InitializePlanets();
     doPlanetRandomize();
     PlanetCounter++;
     if (ProvideHomeworlds)
     {
         HomeRestart++;

         if ((!TestMode)&&(HomeRestart==1)) Info("Initializing Homeworlds...");
         if ((!TestMode)&&(HomeRestart==2)&&(!ShowWait)) { Info("Please wait..."); ShowWait=True;}
         PlanetCounter = MaxPlanetCounter+1;
         MapCounter    = MaxMapCounter+1;

         for(i=1;i<=RACE_NR;i++)
         if (RaceIsPlaying[i])
         {
          for(j=i+1;j<=RACE_NR;j++)
           if ((RaceIsPlaying[j])&&(Homeworlds_[i]==Homeworlds_[j]))
               ErrorExit("Check provided homeworlds. Two IDs are equal.");

           if ((Homeworlds_[i]==0))
             if (OwnedPlanets[i]>0)
               ErrorExit("Check provided homeworlds. Race %d has 0 as homeworld ID.",i);
         }
         for(i=1;i<=RACE_NR;i++)
          if (RaceIsPlaying[i]) Homeworlds[i]=Homeworlds_[i];

         doHomeworlds();

         HWOk=True;
     }
     else
     {    /* !ProvideHomeworlds */
     for (i=1;i<=PLANET_NR;i++)
     if (XYisPlanet[i])
     {
      if (XYCanBeHW[i]) CanBeHW[i]=True;
      else              CanBeHW[i]=False;
     }

/* If minerals or/and natives cash check conditions are set, delete not useable planets as HW */
     if (NativeCashCheck)
     {
     pom1=NativeCashSearchRadius*NativeCashSearchRadius;
     for (i=1;i<=PLANET_NR;i++)
     if (XYisPlanet[i])
      if (CanBeHW[i]==True)
         {
          NatCash[0]=0;
          for (j=1;j<=PLANET_NR;j++)
           if (XYisPlanet[j])
            if  (i!=j)
             if (PlanetDist2(i,j)<=pom1)
               NatCash[0]+=GlobalNatCash[j];
               
          if ((NatCash[0]>NativeCash[1])||(NatCash[0]<NativeCash[0]))
               CanBeHW[i]=False;
         }
     }
     HW=0;
     for (i=1;i<=PLANET_NR;i++)
       if (XYisPlanet[i])
         if (CanBeHW[i]) HW++;

     if (HW>=RiG)
     {

     if (MineCheck)
     {
     pom1=MineSearchRadius*MineSearchRadius;
     for (i=1;i<=PLANET_NR;i++)
     if (XYisPlanet[i])
      if (CanBeHW[i]==True)
         {
          MineT=0;
          MineD=0;
          MineM=0;

          for (j=1;j<=PLANET_NR;j++)
           if (XYisPlanet[j])
            if (i!=j)
             if (PlanetDist2(i,j)<=pom1)
           {
             MineT+=GlobalMineT[j];
             MineD+=GlobalMineD[j];
             MineM+=GlobalMineM[j];
           }

          if ((MineT>MineTritanium[1]  )||(MineT<MineTritanium[0]  ))  CanBeHW[i]=False;
          if ((MineD>MineDuranium[1]   )||(MineD<MineDuranium[0]   ))  CanBeHW[i]=False;
          if ((MineM>MineMolybdenium[1])||(MineM<MineMolybdenium[0]))  CanBeHW[i]=False;
         }
     }
     
     HW=0;
     for (i=1;i<=PLANET_NR;i++)
      if (XYisPlanet[i])
        if (CanBeHW[i]) HW++;

     if (HW>=RiG)
     {
      HomeRestart++;
      if ((!TestMode)&&(HomeRestart==1)) Info("Initializing Homeworlds...");
      if ((!TestMode)&&(HomeRestart==2)&&(!ShowWait)) { Info("Please wait..."); ShowWait=True;}
      if ((HWOk=SearchHomeworlds())==True)
        {
          if (!TestMode) doHomeworlds();
          /* stop searching */
          PlanetCounter = MaxPlanetCounter+1;
          MapCounter    = MaxMapCounter+1;

          /* show homeworld statistic if needed */
          /* not working in test mode */
          if ((HomeInfo)&&(!TestMode))
            if ((NativeCashCheck)||(NearFarPlanetCheck)||(MineCheck))
              ShowHomeInfo();

         } /* homeworld found */
        } /* HW>RiG  after cash */
       } /* HW>RiG  after mines */
      } /*providehomeworlds */
     } /* PlanetCounter */

     if (TestMode)
     {
     if (TestType==1)
     {
     LocalTestNumber++;

     TestGo=True;
     if (LocalTestNumber>=TestModeNumber)
     {
     /* we finish TestMode==1 */
      TestGo=False;
      TestGoGo=False;
      MapCounter=MaxMapCounter+1;
     }
     if (!HWOk) {
       /* check number of tests  */
       if (LocalTestNumber>=TestModeNumber) HWOk=True;
       TestFail++;
       if (HomeProg) ConOut("-");
       else Info("Test %d fail.",LocalTestNumber);
       } /* (!HWOk) */
     else
      {
        /* sucessfull test ? */
        TestCanCopy=0;
        
        /* check is needed home is selected */
        for (k=1;k<=RACE_NR;k++)
         if (RaceIsPlaying[k])
           for(j=0;j<(int)TestModeHomeNumber;j++)
            if (Homeworlds[k]==TestModeHome[j]) TestCanCopy++;

        if (TestCanCopy==TestModeHomeNumber)
        {
        for (k=1;k<=RACE_NR;k++)
         if (RaceIsPlaying[k])
           TestHome[Homeworlds[k]]++;
        Full++;

        if (Statistics)
        {
          PlanetStatistics(Stats);
          for (k=0;k<STATS_NUMBER;k++)
           TestStats[k] = (TestStats[k]*StatCounter + Stats[k])/
                          (StatCounter+1);
          StatCounter++;
        }

        if (Algorithm)
        {
          CountPlanets(PCounts);
          for (k=0;k<6;k++)
           TestPCounts[k] = (TestPCounts[k]*PCounter + PCounts[k])/
                          (PCounter+1);
          PCounter++;
        }
        
        if (HomeProg) ConOut("+");
        }
        else
        /* test completed but needed home ID not selected. */
        if (HomeProg) ConOut("=");
      } /* (HWOk) */
        } /* testtype ==1 */

        if (TestType==2) TestGo=False;
     } /* (TestMode) */
     else
      {
      TestGo=False; /* stop when not in test mode */
      if (HWOk)
        TestGoGo=False; /* finally stop when not in test mode */
       
      }
     } /* test mode */

    } /* HW>=RiG  after far, near */
   } /* MapCounter */

   if (TestMode)
   {
    if (TestType==2)
      {
         LocalTestNumber++;
         MapCounter=0;
         TestGo=True;
         TestGoGo=True;

         if (LocalTestNumber>=TestModeNumber)
         {
         /* we finish TestMode==2 */
          TestGo=False;
          TestGoGo=False;
         }

         if (!HWOk) {
           /* check number of tests  */
           if (LocalTestNumber>=TestModeNumber) HWOk=True;
           TestFail++;
           if (HomeProg) ConOut("-");
           else Info("Test %d fail.",LocalTestNumber);
           } /* (!HWOk) */
         else
           {
            if (Statistics)
            {
              PlanetStatistics(Stats);
              for (k=0;k<STATS_NUMBER;k++)
               TestStats[k] = (TestStats[k]*StatCounter + Stats[k])/
                              (StatCounter+1);
              StatCounter++;
            }
    
            if (Algorithm)
            {
              CountPlanets(PCounts);
              for (k=0;k<6;k++)
               TestPCounts[k] = (TestPCounts[k]*PCounter + PCounts[k])/
                              (PCounter+1);
              PCounter++;
            }

            Full++;
            if (HomeProg) ConOut("+");
           }
        
      } /* test type==2 */
   } /* test mode */
   else
      {
      TestGo=False; /* allways stop when not in test mode */
      TestGoGo=False; /* allways stop when not in test mode */
      }
  } /*testgogo */
  
/* Cannot go further if homeworlds not found */
    if ((!HWOk)&&(!TestMode))
    {
       Error    ("Homeworlds cannot be found !");
       ErrorExit("Change parameters in config file or run again.");
    }
/* Test mode display information and exit */
    if (TestMode)
    {

    if (TestType==1)
    {
      /* sort planets */
     for (i=1;i<=PLANET_NR-1;i++)
     {
        k = i + 1;
        for (j=i+2;j<=PLANET_NR;j++)
            if (TestHome[j]>TestHome[k])
                k=j;
        if (TestHome[k]>TestHome[i])
        {
            pom = TestHome[k];
            TestHome[k]=TestHome[i];
            TestHome[i]=pom;
            pom = BestHome[k];
            BestHome[k]=BestHome[i];
            BestHome[i]=pom;
        }
     }

     /* display */
     if (HomeProg) ConOut("\n\r");
     
     pom = TestModeNumber-TestFail;

     Info("Test completed in %d of %d tries. (%6.2f %%)",
         pom,TestModeNumber,(double)pom/(double)TestModeNumber*100.0);
     if (TestModeHomeNumber)
     {
       tmp1[0]=0;
       strcat(tmp1,(j==1?" ":"s "));
       
       for(j=0;j<(int)TestModeHomeNumber;j++)
       {
         sprintf(tmp2,"ID %ld%s",TestModeHome[j],(j!=(int)TestModeHomeNumber-1?" and ":""));
         strcat(tmp1,tmp2);
       }
     
      Info("Planet%s found in %d of %d cases. (%6.2f %%)"
        ,tmp1,Full,pom,(pom!=0?(double)Full/(double)pom*100.0:0));
     }
     for (i=1;i<=min(PLANET_NR,TestModeDisplay);i++)
     if (TestHome[i]>0)
     {
      if (!TestModeHome)
        Info("ID:%-3d #%-3d %6.2f %%",BestHome[i],TestHome[i],(double)TestHome[i]/(double)pom*100.0);
      else
        Info("ID:%-3d #%-3d %6.2f %%",BestHome[i],TestHome[i],(Full!=0?(double)TestHome[i]/(double)Full*100.0:0));
     }
     } /* test type ==1 */

    if (TestType==2)
    {
          /* display */
     if (HomeProg) ConOut("\n\r");
     
     pom = TestModeNumber-TestFail;

     Info("Test completed in %d of %d tries. (%6.2f %%)",
         pom,TestModeNumber,(double)pom/(double)TestModeNumber*100.0);
     } /* test type ==2 */
     
     if (Statistics)
     {
      if (( (TestType==1)&&(((TestModeHomeNumber)&&(Full))||(!TestModeHomeNumber)) )||
          ( (TestType==2)&&(Full) ) )
        ShowPlanetStatistics(TestStats);
      else
        Info("There were no sucessfull cases to gather -t statistics.");
     }
     
     if (Algorithm)
      {
      if (( (TestType==1)&&(((TestModeHomeNumber)&&(Full))||(!TestModeHomeNumber)) )||
          ( (TestType==2)&&(Full) ) )
       ShowCountPlanets(TestPCounts);
      else
        Info("There were no sucessfull cases to gather -g statistics.");
      }
    }

    if (!TestMode)
    {
     if (MapRestart > 1 ) Info("Map creation restarted %d times",MapRestart);
     if (PlanetRestart > 1 ) Info("Planets creation restarted %d times",PlanetRestart);
     if (HomeRestart > 1 ) Info("Homeworlds search restarted %d times",HomeRestart);

 /* Mark  players as active */
     Info("Initializing Players...");

     for (i = 1; i <= RACE_NR; i++)
        PutPlayerIsActive(i, RaceIsPlaying[i]);

     if (!(strcmp(Password1,"none"))&&(RaceIsPlaying[1]))
     PutPlayerPassword(1, "");
     else
     PutPlayerPassword(1, Password1);

     if (!(strcmp(Password2,"none"))&&(RaceIsPlaying[2]))
     PutPlayerPassword(2, "");
     else
     PutPlayerPassword(2, Password2);

     if (!(strcmp(Password3,"none"))&&(RaceIsPlaying[3]))
     PutPlayerPassword(3, "");
     else
     PutPlayerPassword(3, Password3);

     if (!(strcmp(Password4,"none"))&&(RaceIsPlaying[4]))
     PutPlayerPassword(4, "");
     else
     PutPlayerPassword(4, Password4);

     if (!(strcmp(Password5,"none"))&&(RaceIsPlaying[5]))
     PutPlayerPassword(5, "");
     else
     PutPlayerPassword(5, Password5);

     if (!(strcmp(Password6,"none"))&&(RaceIsPlaying[6]))
     PutPlayerPassword(6, "");
     else
     PutPlayerPassword(6, Password6);

     if (!(strcmp(Password7,"none"))&&(RaceIsPlaying[7]))
     PutPlayerPassword(7, "");
     else
     PutPlayerPassword(7, Password7);

     if (!(strcmp(Password8,"none"))&&(RaceIsPlaying[8]))
     PutPlayerPassword(8, "");
     else
     PutPlayerPassword(8, Password8);

     if (!(strcmp(Password9,"none"))&&(RaceIsPlaying[9]))
     PutPlayerPassword(9, "");
     else
     PutPlayerPassword(9, Password9);

     if (!(strcmp(Password10,"none"))&&(RaceIsPlaying[10]))
     PutPlayerPassword(10, "");
     else
     PutPlayerPassword(10, Password10);

     if (!(strcmp(Password11,"none"))&&(RaceIsPlaying[11]))
     PutPlayerPassword(11, "");
     else
     PutPlayerPassword(11, Password11);

     Info( "Initializing HomePlanets...");
     searchPlanetsBases();
     doHomePlanets();

     Info( "Initializing Bases...");
     doBases();

     if (FreeShips)
     {
     Info( "Initializing Ships...");
     doShips();
     }

     if (WormGen&&CreateWormholes)
     {
     Info("Initializing Wormholes...");
     doWormhole();
     }

/*  Create GREY.HST file. If needed generate Ion Storms and save them in GREY.HST */
     if (CreateIonStorms)
      Info("Initializing Ion Storms...");
     doGrey();
     doRefData();

     Info( "Writing out...");

 /* Write out our universe. */
     if (!Write_Planets_File(PLANET_NR))
          ErrorExit("Cannot write planet file.");
     if (!Write_Ships_File(MaxShips))
          ErrorExit("Cannot write ship file.");
     if (!Write_Bases_File(PLANET_NR, 0))
          ErrorExit("Cannot write base file.");
     if (!Write_Mines_File())
          ErrorExit("Cannot write mines file.");
     if (!Write_AuxData_File())
          ErrorExit("Cannot write AuxData file.");
     if (!Write_HostGen_File())
          ErrorExit("Cannot write GEN.HST file.");

 /* The turntime file NEXTTURN.HST is of 0 length after mastering */
     f= OpenOutputFile("nextturn.hst", GAME_DIR_ONLY);
     if (f!=NULL) fclose(f);
     else         ErrorExit("Cannot write NEXTTURN.HST file.");

     if (WriteMess)
     {
       sprintf(tmp1," v%u.%u%c ",pMajor, pMinor, pLetter);
       strncpy(tmp2,"(-a0000)<< AMASTER",49);
       strcat(tmp2,tmp1);
       strcat(tmp2,">>\r");
       strcat(tmp2,"\rThis universe was created\r");
       strcat(tmp2,"by AMaster");
       strcat(tmp2,tmp1);
       strcat(tmp2,"\r\r");
       strcat(tmp2,"Have fun.\r");

       for (i = 1; i <= RACE_NR; i++)
       if (RaceIsPlaying[i]) WriteExternalMessage(i,tmp2);
     }

     Info ("Mastering done.");

     if (Statistics)
     {
       PlanetStatistics(Stats);
       ShowPlanetStatistics(Stats);
     }
     
     if (Algorithm)
     {
       CountPlanets(PCounts);
       ShowCountPlanets(PCounts);
     }
     
     if (ShowIDs)      ShowPlayersPIDs();

     if (ShowNumbers)  ShowPlayersInfo();

     } /* !TestMode */

     e_time=time(NULL)-s_time;

     sec_time=(int)e_time%60;
     min_time=(int)e_time/60;
     if (ShowTTime) Info("Total run time :  %02d:%02d",min_time,sec_time);

/* Close down. */

     if (logF==True)
       if (gLogFile!=NULL) fclose(gLogFile);

     FreePHOSTLib();

     return EXIT_SUCCESS;
}

/**************************************************************************/
void config_int_8 (int i, int value[11])
{
  int j;

  switch (i)
  {
   case   1: for (j=0;j<8;j++) PlanetSurfaceRanges[j]=value[j]; break;
   case   2: for (j=0;j<8;j++) PlanetDensityRanges[j]=value[j]; break;
   case  15: for (j=0;j<8;j++) PlanetCoreRangesUsual[j]=value[j]; break;
   case  16: for (j=0;j<8;j++) PlanetCoreRangesAlternate[j]=value[j]; break;
   case 115: for (j=0;j<8;j++) DefaultHomePlanet[j]=value[j]; break;
  }
}

void config_int_4 (int i, int value[11])
{
  int j;

  switch (i)
  {
   case 14: for (j=0;j<4;j++) PlanetCoreUsualFrequency[j]=value[j]; break;
   case 24: for (j=0;j<4;j++) HomeworldsRange[j]=value[j]; break;
   case 64: for (j=0;j<4;j++) WormholeStartRange[j]=value[j]; break;
   case 65: for (j=0;j<4;j++) WormholeEndRange[j]=value[j]; break;
   case 98: for (j=0;j<4;j++) WraparoundRectangle[j]=value[j]; break;
   case 114: for (j=0;j<4;j++) IonStormsCenterRange[j]=value[j]; break;
   }
}

void config_int_9 (int i, int value[11])
{
  int j;

  switch (i)
  {
   case 18: for (j=1;j<10;j++) NativeTypeFrequencies[j]=value[j-1]; break;
   case 19: for (j=1;j<10;j++) NativeGovFrequencies[j]=value[j-1]; break;

  }
}

void config_int_2 (int i, int value[11])
{
  int j;

  switch (i)
  {
   case 20: for (j=0;j<2;j++) NativeRange[j]=value[j]; break;
   case 31: for (j=0;j<2;j++) BaseHopsLimit[j]=value[j]; break;
   case 49: for (j=0;j<2;j++) NearPlanetsNo[j]=value[j]; break;
   case 51: for (j=0;j<2;j++) FarPlanetsNo[j]=value[j]; break;
   case 50: for (j=0;j<2;j++) MineTritanium[j]=value[j]; break;
   case 52: for (j=0;j<2;j++) MineDuranium[j]=value[j]; break;
   case 57: for (j=0;j<2;j++) MineMolybdenium[j]=value[j]; break;
   case 56: for (j=0;j<2;j++) NativeCash[j]=value[j]; break;
   case 66: for (j=0;j<2;j++) WormholeInstabilityRange[j]=value[j]; break;
   case 67: for (j=0;j<2;j++) WormholeMassRange[j]=value[j]; break;
   case 105: for (j=0;j<2;j++) PlanetsTempRange[j]=value[j]; break;
   case 106: for (j=0;j<2;j++) OwnedPlanetsTempRange[j]=value[j]; break;
   case 109: for (j=0;j<2;j++) IonStormsVoltageRange[j]=value[j]; break;
   case 110: for (j=0;j<2;j++) IonStormsRadiusRange[j]=value[j]; break;
  }
}

void config_bool (int i, Boolean value)
{
  switch (i)
  {
   case 23: NoAmorphousOnHomePlanets=value; break;
   case 30: AdjustBasesTechs=value; break;
   case 33: AllowWraparoundMap=value;
            if (value==False)
            {
             if (config[24].read==2) config[24].read=False;
            }
            break;
   case 36: CrystalsPreferDeserts=value; break;
   case 47: AllOwnedPlanetsTheSame=value; break;
   case 48: BioSupport=value;
            if (value==True)
            {
             if (config[104].read==2) config[104].read=False;
             if (config[105].read==2) config[105].read=False;
             if (config[106].read==2) config[106].read=False;
            }
            break;
   case 53: NearFarPlanetCheck=value;
            if (value==True)
            {
             if (config[49].read==2) config[49].read=False;
             if (config[51].read==2) config[51].read=False;
             if (config[74].read==2) config[74].read=False;
             if (config[75].read==2) config[75].read=False;
            }
            break;

   case 54: NativeCashCheck=value;
            if (value==True)
            {
              if (config[56].read==2) config[56].read=False;
              if (config[58].read==2) config[58].read=False;
            }
            break;

    case 70: MineCheck=value;
            if (value==True)
            {
               if (config[50].read==2) config[50].read=False;
               if (config[52].read==2) config[52].read=False;
               if (config[57].read==2) config[57].read=False;
               if (config[72].read==2) config[72].read=False;
               if (config[73].read==2) config[73].read=False;
            }
            break;

   case 59: CreateWormholes=value;
            if (value==True)
            {
              if (config[60].read==2) config[60].read=False;
              if (config[61].read==2) config[61].read=False;
              if (config[62].read==2) config[62].read=False;
              if (config[63].read==2) config[63].read=False;
              if (config[64].read==2) config[64].read=False;
              if (config[65].read==2) config[65].read=False;
              if (config[66].read==2) config[66].read=False;
              if (config[67].read==2) config[67].read=False;
              if (config[96].read==2) config[96].read=False;
              if (config[97].read==2) config[97].read=False;
              if (config[99].read==2) config[99].read=False;
              if (config[100].read==2) config[100].read=False;
              if (config[101].read==2) config[101].read=False;
              if (config[102].read==2) config[102].read=False;
              if (config[103].read==2) config[103].read=False;
            }
            break;

   case 68: CreateMap=value;
            if (value==True)
            {
              if (config[69].read==2)  config[69].read=False;
              if (config[134].read==2) config[134].read=False;
              if (config[135].read==2) config[135].read=False;
            }
            break;

   case 76: FreeShips=value;
            if (value==True)
            {
              if (config[29].read==2) config[29].read=False;
              if (config[77].read==2) config[77].read=False;
              if (config[78].read==2) config[78].read=False;
              if (config[79].read==2) config[79].read=False;
              if (config[80].read==2) config[80].read=False;
              if (config[81].read==2) config[81].read=False;
              if (config[82].read==2) config[82].read=False;
              if (config[90].read==2) config[90].read=False;
            }
            break;

   case 78: FreeShipsAllTheSame=value; break;
   case 86: AllBasesTheSame=value; break;
   case 96: NoWormholesNearHomeworlds=value; break;
   case 99: NoWormholesNearPlanets=value; break;
   case 107: AdjustPopulations=value; break;
   case 108: CreateIonStorms=value;
            if (value==True)
            {
              if (config[109].read==2) config[109].read=False;
              if (config[110].read==2) config[110].read=False;
              if (config[111].read==2) config[111].read=False;
              if (config[112].read==2) config[112].read=False;
              if (config[113].read==2) config[113].read=False;
              if (config[114].read==2) config[113].read=False;
            }
            break;
   case 112: NoIonStormsNearHomeworlds=value; break;
   case 116: AllPlayerPlanetsTheSame=value; break;
   case 121: MapTruehullByPlayerRace=value; break;
   case 122: CrystalSinTempBehavior=value; break;
   case 123: ClimateLimitsPopulation=value; break;
   case 130: ProvideHomeworlds=value; break;
   case 133: BindPlanetsToBases=value; break;
   case 135: FixMapChecksums=value; break;
   }
}


void config_int (int i, int value)
{
  switch (i)
  {
   case  17 : NativesOnPlanetFrequency=value; break;
   case  25 : DefaultNativesHappy=value;      break;
   case  26 : DefaultColonistHappy=value;     break;
   case  27 : BaseHopsNumber=value;           break;
   case  28 : BaseHopsFactor=value;           break;
   case  32 : HomeworldsRadius=value;         break;
   case  34 : BorderWidth=value;              break;
   case  58:  NativeCashSearchRadius=value;   break;
   case  60:  WormholeNumber=value;           break;
   case  61:  WormholeUniDirChance=value;     break;
   case  62:  WormholeStartMoveChance=value;  break;
   case  63:  WormholeEndMoveChance=value;    break;
   case  69:  PlanetsMinDistance=value;       break;
   case  72:  MineSearchRadius=value;         break;
   case  73:  MaxMineTurns=value;             break;
   case  74:  NearSearchRadius=value;         break;
   case  75:  FarSearchRadius=value;          break;
   case  79:  FreeShipsHull=value;            break;
   case  80:  FreeShipsEngines=value;         break;
   case  81:  FreeShipsBeams=value;           break;
   case  82:  FreeShipsTubes=value;           break;
   case  90:  FreeShipsAmmo=value;            break;

   case  71:  MaxMapCounter=value;            break;
   case  55:  MaxPlanetCounter=value;         break;
   case  95:  MaxHWCounter=value;             break;
   case  97:  MinWormHomeDistance=value;      break;

   case  100:  MinWormPlanetDistance=value;   break;
   case  101:  MinWormholesDistance=value;    break;
   case  102:  MaxWormholesCounter=value;     break;
   case  103:  MinWormholeLength=value;       break;
   case  104:  BioSupportLevel=value;         break;

   case  111:  IonStormsNumber=value;         break;
   case  113:  MinIonStormsHomeDistance=value; break;
   case  132:  MaxColTempSlope=value;         break;
   case  134:  PlanetsNumber=value;           break;

   case  136:  HomeworldsMaxRadius=value;     break;
   }
}

void config_string (int i, const char *value)
{
  switch (i)
  {
   case  3 : strncpy(Password1,value,10); break;
   case  4 : strncpy(Password2,value,10); break;
   case  5 : strncpy(Password3,value,10); break;
   case  6 : strncpy(Password4,value,10); break;
   case  7 : strncpy(Password5,value,10); break;
   case  8 : strncpy(Password6,value,10); break;
   case  9 : strncpy(Password7,value,10); break;
   case  10 : strncpy(Password8,value,10); break;
   case  11 : strncpy(Password9,value,10); break;
   case  12 : strncpy(Password10,value,10); break;
   case  13 : strncpy(Password11,value,10); break;
  }
}

void config_int_11_o (int i, int value[11])
{
  int j;

  switch (i)
  {
   case 21: for (j=1;j<=RACE_NR;j++) OwnedPlanets[j]=value[j-1]; break;
   case 22: for (j=1;j<=RACE_NR;j++) OwnedBases[j]=value[j-1]; break;
   case 35: for (j=1;j<=RACE_NR;j++) HomeworldClans[j]=value[j-1]; break;
   case 37: for (j=1;j<=RACE_NR;j++) HomeworldCash[j]=value[j-1]; break;
   case 38: for (j=1;j<=RACE_NR;j++) HomeworldCoreN[j]=value[j-1]; break;
   case 39: for (j=1;j<=RACE_NR;j++) HomeworldCoreT[j]=value[j-1]; break;
   case 40: for (j=1;j<=RACE_NR;j++) HomeworldCoreD[j]=value[j-1]; break;
   case 41: for (j=1;j<=RACE_NR;j++) HomeworldCoreM[j]=value[j-1]; break;
   case 42: for (j=1;j<=RACE_NR;j++) HomeworldSurfaceN[j]=value[j-1]; break;
   case 43: for (j=1;j<=RACE_NR;j++) HomeworldSurfaceT[j]=value[j-1]; break;
   case 44: for (j=1;j<=RACE_NR;j++) HomeworldSurfaceD[j]=value[j-1]; break;
   case 45: for (j=1;j<=RACE_NR;j++) HomeworldSurfaceM[j]=value[j-1]; break;
   case 46: for (j=1;j<=RACE_NR;j++) StartingEngineTech[j]=value[j-1]; break;
   case 77: for (j=1;j<=RACE_NR;j++) FreeShipsNumber[j]=value[j-1]; break;
   case 83: for (j=1;j<=RACE_NR;j++) BaseFreeDefence[j]=value[j-1]; break;
   case 84: for (j=1;j<=RACE_NR;j++) BaseFreeFighters[j]=value[j-1]; break;
   case 87: for (j=1;j<=RACE_NR;j++) StartingHullTech[j]=value[j-1]; break;
   case 88: for (j=1;j<=RACE_NR;j++) StartingBeamTech[j]=value[j-1]; break;
   case 89: for (j=1;j<=RACE_NR;j++) StartingTubeTech[j]=value[j-1]; break;
   case 91: for (j=1;j<=RACE_NR;j++) HomeworldDensityN[j]=value[j-1]; break;
   case 92: for (j=1;j<=RACE_NR;j++) HomeworldDensityT[j]=value[j-1]; break;
   case 93: for (j=1;j<=RACE_NR;j++) HomeworldDensityD[j]=value[j-1]; break;
   case 94: for (j=1;j<=RACE_NR;j++) HomeworldDensityM[j]=value[j-1]; break;
   case 124: for (j=1;j<=RACE_NR;j++) HomeworldMines[j]=value[j-1]; break;
   case 125: for (j=1;j<=RACE_NR;j++) HomeworldFactories[j]=value[j-1]; break;
   case 126: for (j=1;j<=RACE_NR;j++) HomeworldDefence[j]=value[j-1]; break;
   case 127: for (j=1;j<=RACE_NR;j++) HomeworldSupplies[j]=value[j-1]; break;
   case 128: for (j=1;j<=RACE_NR;j++) HomeworldColonistTax[j]=value[j-1]; break;
   case 129: for (j=1;j<=RACE_NR;j++) HomeworldColonistHappy[j]=value[j-1]; break;
   }
}

void config_int_11 (int i, int value[11])
{
  int j;

  switch (i)
  {
  case 131: for (j=1;j<=RACE_NR;j++) Homeworlds_[j]=value[j-1]; break;
  case 120: for (j=1;j<=RACE_NR;j++) PlayerRace[j]=value[j-1]; break;
  }
}

void config_bool_11_o (int i, int value[11])
{
  int j;

  switch (i)
  {
   case 0: for (j=1;j<=RACE_NR;j++) RaceIsPlaying[j]=value[j-1]; break;
   case 29: for (j=1;j<=RACE_NR;j++) FreeShipsOnBases[j]=value[j-1]; break;
   case 85: for (j=1;j<=RACE_NR;j++) BaseFreeHulls[j]=value[j-1]; break;
   case 117: for (j=1;j<=RACE_NR;j++) BaseFreeEngines[j]=value[j-1]; break;
   case 118: for (j=1;j<=RACE_NR;j++) BaseFreeBeams[j]=value[j-1]; break;
   case 119: for (j=1;j<=RACE_NR;j++) BaseFreeTorps[j]=value[j-1]; break;
  }
}

Boolean my_func(const char *lhs, char *rhs, const char *lInputLine)
{
  int i,tmp_int,tmp_,j,k,errorno;
  int tmp_int11[11];
  char tmp1[200],tmp2[200];
  char tmp3[11][80];
  Boolean line_ok,val_ok,still_not;
  Uns16 pID;

  if ((lhs==NULL)&&(rhs==NULL)) return True;

  line_ok = False;
  errorno=4;
  still_not=True;

/* check for planetX params */

  strncpy(tmp1,lInputLine,199); /* Dumb copy */
  strncpy(tmp1,lhs,199);
  strupr(tmp1);
  tmp1[strlen(tmp1)-1]=0;

  if (strcmp(tmp1,"PLANET")==0)
  {
    pID=lhs[strlen(lhs)-1]-'1'+1;
    still_not=False;
  }

  /* check for planetXX params */

  strncpy(tmp1,lhs,199);
  strupr(tmp1);
  tmp1[strlen(tmp1)-2]=0;

  if (strcmp(tmp1,"PLANET")==0)
  {
    pID=(lhs[strlen(lhs)-2]-'1'+1)*10+lhs[strlen(lhs)-1]-'1'+1;
    still_not=False;
  }


  if (!still_not)
  {
    tmp_=sscanf(rhs,"%d,%d,%d,%d,%d",
                    &tmp_int11[0],&tmp_int11[1],&tmp_int11[2],
                    &tmp_int11[3],&tmp_int11[4] );
/*  wrong value */
    if (tmp_!=5)
       { errorno=1; line_ok = False;  }
    else
    {
/* values check */
    val_ok=True;
/* native type */
    if ((tmp_int11[0]<-2)||(tmp_int11[0]>9)) val_ok=False;
/* native gov */
    if ((tmp_int11[1]<-1)||(tmp_int11[1]>9)) val_ok=False;
/* native clans */
    if ((tmp_int11[2]<-1)||(tmp_int11[2]>154000)) val_ok=False;
/* native happy */
    if ((tmp_int11[3]<-1)||(tmp_int11[3]>100)) val_ok=False;
/* native tax */
    if ((tmp_int11[4]<-1)||(tmp_int11[4]>100)) val_ok=False;

    if (!val_ok)
       { errorno=3; line_ok = False;}
     else
     {
     for (i=0;i<5;i++) PlanetsNat[pID-1][i]=tmp_int11[i];
     line_ok=True;
     }
    } /* value ok */
  }


  if (still_not)
/* check for homeplanetX params */
  {
  strncpy(tmp1,lhs,199);
  strupr(tmp1);
  tmp1[strlen(tmp1)-1]=0;

  if (strcmp(tmp1,"HOMEPLANET")==0)
  {
    pID=lhs[strlen(lhs)-1]-'1'+1;
    still_not=False;
  }

  /* check for homeplanetXX params */

  strncpy(tmp1,lhs,199);
  strupr(tmp1);
  tmp1[strlen(tmp1)-2]=0;

  if (strcmp(tmp1,"HOMEPLANET")==0)
  {
    pID=(lhs[strlen(lhs)-2]-'1'+1)*10+lhs[strlen(lhs)-1]-'1'+1;
    still_not=False;
  }


  if (!still_not)
  {
    tmp_=sscanf(rhs,"%d,%d,%d,%d,%d,%d,%d,%d",
                    &tmp_int11[0],&tmp_int11[1],&tmp_int11[2],
                    &tmp_int11[3],&tmp_int11[4],&tmp_int11[5],
                    &tmp_int11[6],&tmp_int11[7] );
/*  wrong value */
    if (tmp_!=8)
       { errorno=1; line_ok = False;  }
    else
    {
/* values check */
    val_ok=True;
    for (k=0;k<8;k++)
      if ((tmp_int11[k]<0)||(tmp_int11[k]>(int)MAX16)) val_ok=False;

    if (!val_ok)
       { errorno=3; line_ok = False;}
     else
     {
     for (i=0;i<8;i++) HomePlanet[pID-1][i]=tmp_int11[i];
     PlanetsRead[pID-1]=1;
     line_ok=True;
     }
    } /* value ok */
  }



  if (still_not)
  for (i=0;i<PARAM_NUMBER;i++)
  {
     strncpy(tmp1,lhs,199);
     strupr(tmp1);
     strncpy(tmp2,config[i].name,199);
     strupr(tmp2);
     if (strcmp(tmp1,tmp2)==0)
     {
        line_ok=True;

        if (config[i].mode==CONFIG_BOOL)
        {
          strncpy(tmp1,rhs,199);
          strupr(tmp1);
          if ((strcmp(tmp1,"TRUE")==0)||(strcmp(tmp1,"YES")==0))
          {
            config_bool(i,True);
            config[i].read=True;
            break;
          }
          else
          if ((strcmp(tmp1,"FALSE")==0)||(strcmp(tmp1,"NO")==0))
          {
            config_bool(i,False);
            config[i].read=True;
            break;
          }
          else
/*  wrong value */
          { errorno=2; line_ok = False;  break; }
        }  /* bool */
        if (config[i].mode==CONFIG_BOOL11_O)
        {
/* string prepearation */
          strncpy(tmp1,rhs,199);
          strupr(tmp1);
          while (strstr(tmp1,",")!=NULL) strstr(tmp1,",")[0]=' ';
          while (strstr(tmp1,".")!=NULL) strstr(tmp1,",")[0]=' ';
          tmp_=sscanf(tmp1,"%s %s %s %s %s %s %s %s %s %s %s",
                          tmp3[0],tmp3[1],tmp3[2],tmp3[3],
                          tmp3[4],tmp3[5],tmp3[6],tmp3[7],
                          tmp3[8],tmp3[9],tmp3[10] );
           if ((tmp_!=1)&&(tmp_!=11))
              { errorno=2; line_ok = False; break; }

           if (tmp_==1)
           {
           if ((strcmp(tmp3[0],"TRUE")==0)||(strcmp(tmp3[0],"YES")==0))
            tmp_int11[0]=True;
           else
           if ((strcmp(tmp3[0],"FALSE")==0)||(strcmp(tmp3[0],"NO")==0))
            tmp_int11[0]=False;
           else
            { errorno=2; line_ok = False; break; }

            tmp_int11[1]=tmp_int11[0];
            tmp_int11[2]=tmp_int11[0];
            tmp_int11[3]=tmp_int11[0];
            tmp_int11[4]=tmp_int11[0];
            tmp_int11[5]=tmp_int11[0];
            tmp_int11[6]=tmp_int11[0];
            tmp_int11[7]=tmp_int11[0];
            tmp_int11[8]=tmp_int11[0];
            tmp_int11[9]=tmp_int11[0];
            tmp_int11[10]=tmp_int11[0];
            config_bool_11_o(i,tmp_int11);
            config[i].read=True;
           }
           else /* tmp_==11 */
          {

          for (j=0;j<11;j++)
          if ((strcmp(tmp3[j],"TRUE")==0)||(strcmp(tmp3[j],"YES")==0))
            tmp_int11[j]=True;
           else
           if ((strcmp(tmp3[j],"FALSE")==0)||(strcmp(tmp3[j],"NO")==0))
            tmp_int11[j]=False;
           else
             { errorno=2; line_ok = False;  break; }

          /* end for */
            config_bool_11_o(i,tmp_int11);
            config[i].read=True;
          }

        }  /* bool11_o  */

      if (config[i].mode==CONFIG_INT11_O)
        {
           tmp_=sscanf(rhs,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
                           &tmp_int11[0],&tmp_int11[1],&tmp_int11[2],
                           &tmp_int11[3],&tmp_int11[4],&tmp_int11[5],
                           &tmp_int11[6],&tmp_int11[7],&tmp_int11[8],
                           &tmp_int11[9],&tmp_int11[10] );
           if (tmp_==1)
           {
            tmp_int11[1]=tmp_int11[0];
            tmp_int11[2]=tmp_int11[0];
            tmp_int11[3]=tmp_int11[0];
            tmp_int11[4]=tmp_int11[0];
            tmp_int11[5]=tmp_int11[0];
            tmp_int11[6]=tmp_int11[0];
            tmp_int11[7]=tmp_int11[0];
            tmp_int11[8]=tmp_int11[0];
            tmp_int11[9]=tmp_int11[0];
            tmp_int11[10]=tmp_int11[0];
           }
/*  wrong value */
           if ((tmp_!=1)&&(tmp_!=11))
              { errorno=1; line_ok = False; break; }

/* values check */
           val_ok=True;
           for (k=0;k<11;k++)
             if ((tmp_int11[k]<config[i].min)||(tmp_int11[k]>config[i].max)) val_ok=False;
           if (!val_ok)
              { errorno=3; line_ok = False; break; }

           config_int_11_o(i,tmp_int11);
           config[i].read=True;
           break;
        } /* int11_o */


      if (config[i].mode==CONFIG_INT11)
        {
           tmp_=sscanf(rhs,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
                           &tmp_int11[0],&tmp_int11[1],&tmp_int11[2],
                           &tmp_int11[3],&tmp_int11[4],&tmp_int11[5],
                           &tmp_int11[6],&tmp_int11[7],&tmp_int11[8],
                           &tmp_int11[9],&tmp_int11[10] );
/*  wrong value */
           if (tmp_!=11)
              { errorno=1; line_ok = False; break; }

/* values check */
           val_ok=True;
           for (k=0;k<11;k++)
             if ((tmp_int11[k]<config[i].min)||(tmp_int11[k]>config[i].max)) val_ok=False;
           if (!val_ok)
              { errorno=3; line_ok = False; break; }

           config_int_11(i,tmp_int11);
           config[i].read=True;
           break;
        } /* int11_o */

        if (config[i].mode==CONFIG_INT4)
        {
           tmp_=sscanf(rhs,"%d,%d,%d,%d",
                           &tmp_int11[0],&tmp_int11[1],&tmp_int11[2],
                           &tmp_int11[3] );
/*  wrong value */
           if (tmp_!=4)
              { errorno=1; line_ok = False;  break; }
/* values check */
           val_ok=True;
           for (k=0;k<4;k++)
             if ((tmp_int11[k]<config[i].min)||(tmp_int11[k]>config[i].max)) val_ok=False;
           if (!val_ok)
              { errorno=3; line_ok = False; break; }


           config_int_4(i,tmp_int11);
           config[i].read=True;
           break;
        } /* int4  */

        if (config[i].mode==CONFIG_INT2)
        {
           tmp_=sscanf(rhs,"%d,%d",
                           &tmp_int11[0],&tmp_int11[1]);
/* wrong value */
           if (tmp_!=2)
             { errorno=1; line_ok = False;  break; }
/* values check */
           val_ok=True;
           for (k=0;k<2;k++)
             if ((tmp_int11[k]<config[i].min)||(tmp_int11[k]>config[i].max)) val_ok=False;
           if (!val_ok)
              { errorno=3; line_ok = False; break; }
           config_int_2(i,tmp_int11);
           config[i].read=True;
           break;
        } /* int2 */

        if (config[i].mode==CONFIG_INT8)
        {
           tmp_=sscanf(rhs,"%d,%d,%d,%d,%d,%d,%d,%d",
                           &tmp_int11[0],&tmp_int11[1],&tmp_int11[2],
                           &tmp_int11[3],&tmp_int11[4],&tmp_int11[5],
                           &tmp_int11[6],&tmp_int11[7] );
/* wrong value */
           if (tmp_!=8)
              { errorno=1; line_ok = False; break; }
/* values check */
           val_ok=True;
           for (k=0;k<8;k++)
             if ((tmp_int11[k]<config[i].min)||(tmp_int11[k]>config[i].max)) val_ok=False;
           if (!val_ok)
              { errorno=3; line_ok = False; break; }
           config_int_8(i,tmp_int11);
           config[i].read=True;
           break;
        } /* int8 */

        if (config[i].mode==CONFIG_INT9)
        {
           tmp_=sscanf(rhs,"%d,%d,%d,%d,%d,%d,%d,%d,%d",
                           &tmp_int11[0],&tmp_int11[1],&tmp_int11[2],
                           &tmp_int11[3],&tmp_int11[4],&tmp_int11[5],
                           &tmp_int11[6],&tmp_int11[7],&tmp_int11[8] );
/* wrong value */
           if (tmp_!=9)
              { errorno=1; line_ok = False;  break; }
/* values check */
           val_ok=True;
           for (k=0;k<9;k++)
             if ((tmp_int11[k]<config[i].min)||(tmp_int11[k]>config[i].max)) val_ok=False;
           if (!val_ok)
              { errorno=3; line_ok = False; break; }

           config_int_9(i,tmp_int11);
           config[i].read=True;
           break;
        } /* int9 */

        if (config[i].mode==CONFIG_INT)
        {
           tmp_=sscanf(rhs,"%d",&tmp_int);
/* wrong value */
           if (tmp_==0)
              { errorno=1; line_ok = False; break; }
/* values check */
           val_ok=True;
             if ((tmp_int<config[i].min)||(tmp_int>config[i].max)) val_ok=False;
           if (!val_ok)
              { errorno=3; line_ok = False; break; }

           config_int(i,tmp_int);
           config[i].read=True;
           break;
        } /* int  */

        if (config[i].mode==CONFIG_STRING)
        {
           config_string(i,rhs);
           config[i].read=True;
           break;
        } /* string */

     }
  }
  } /* still not 1   */

  if (line_ok)
  {
  ConfigError=False;
  return True;
  }
  else
  {
   switch (errorno)
   {
    case 1: Error("Illegal integer value or not valid number of arguments."); break;
    case 2: Error("Illegal Boolean value or not valid number of arguments."); break;
    case 3: Error("Argument out of range."); break;
    case 4: Error("Not valid AMASTER parameter : %s",lhs); break;
    }
  ConfigError=True;
  return False;
  }
}

void ReadConfig(void)
{
   FILE *f;
   int i;
   Boolean tr;

   f=OpenInputFile(configname,GAME_DIR_ONLY|TEXT_MODE);
   if (f!=NULL)
    {
    ConfigFileReader(f,configname,"AMASTER",False, my_func);
    fclose(f);
    }
   else
    ErrorExit("Cannot open config file.");

   if (ConfigError) ErrorExit("Config file cannot be processed.");

/* check dependable config options for reading from config file
   if main option was not read and is true
   mark needed options (if not in config file) not read */

/* special case AllowWraparoundMap */
  if (config[33].read==False)
            if (AllowWraparoundMap==False)
            {
             if (config[24].read==2) config[24].read=False;
            }

/* special case BioSupport */
  if (config[48].read==False)
            if (BioSupport==True)
            {
             if (config[104].read==2) config[104].read=False;
             if (config[105].read==2) config[105].read=False;
             if (config[106].read==2) config[106].read=False;
            }

/* special case NearFarPlanetCheck */
  if (config[53].read==False)
  {
            if (NearFarPlanetCheck==True)
            {
              if (config[49].read==2) config[49].read=False;
              if (config[51].read==2) config[51].read=False;
              if (config[74].read==2) config[74].read=False;
              if (config[75].read==2) config[75].read=False;
           }
  }
/* special case NativeCashCheck */
  if (config[54].read==False)
  {
            if (NativeCashCheck==True)
            {
              if (config[56].read==2) config[56].read=False;
              if (config[58].read==2) config[58].read=False;
           }
  }
/* special case MineCheck */

 if (config[70].read==False)
            if (MineCheck==True)
            {
               if (config[50].read==2) config[50].read=False;
               if (config[52].read==2) config[52].read=False;
               if (config[57].read==2) config[57].read=False;
               if (config[72].read==2) config[72].read=False;
               if (config[73].read==2) config[73].read=False;
            };

/* special case CreateWormholes */
  if (config[59].read==False)
  {
            if (CreateWormholes==True)
            {
              if (config[60].read==2) config[60].read=False;
              if (config[61].read==2) config[61].read=False;
              if (config[62].read==2) config[62].read=False;
              if (config[63].read==2) config[63].read=False;
              if (config[64].read==2) config[64].read=False;
              if (config[65].read==2) config[65].read=False;
              if (config[66].read==2) config[66].read=False;
              if (config[67].read==2) config[67].read=False;
              if (config[96].read==2) config[96].read=False;
              if (config[97].read==2) config[97].read=False;
              if (config[99].read==2) config[99].read=False;
              if (config[100].read==2) config[100].read=False;
              if (config[101].read==2) config[101].read=False;
              if (config[102].read==2) config[102].read=False;
              if (config[103].read==2) config[103].read=False;
            }
   }
/* special case CreateMap  */
  if (config[68].read==False)
  {
            if (CreateMap==True)
            {
              if (config[69].read==2) config[69].read=False;
              if (config[134].read==2) config[134].read=False;
              if (config[135].read==2) config[135].read=False;
            }
   }

/* special case FreeShips  */
  if (config[76].read==False)
  {
            if (FreeShips==True)
            {
              if (config[29].read==2) config[29].read=False;
              if (config[77].read==2) config[77].read=False;
              if (config[78].read==2) config[78].read=False;
              if (config[79].read==2) config[79].read=False;
              if (config[80].read==2) config[80].read=False;
              if (config[81].read==2) config[81].read=False;
              if (config[82].read==2) config[82].read=False;
              if (config[90].read==2) config[90].read=False;
            }
  }

/* special case Ion Storms */
  if (config[108].read==False)
  {
            if (CreateIonStorms==True)
            {
              if (config[109].read==2) config[109].read=False;
              if (config[110].read==2) config[110].read=False;
              if (config[111].read==2) config[111].read=False;
              if (config[112].read==2) config[112].read=False;
              if (config[113].read==2) config[113].read=False;
              if (config[114].read==2) config[113].read=False;
            }
  }

   tr=False;
   for (i=0;i<PARAM_NUMBER;i++)
   if (config[i].read==False) tr=True;
   if (tr==True)
   {
     Warning("Those parameters were not read from config file.");
     Warning("Setting them to default values.");
     for (i=0;i<PARAM_NUMBER;i++)
     if (config[i].read==False) Info("%s = %s",config[i].name,config[i].name_d);
     Info("");
   }
}

static void doCheck(void)
{
    int i,j;
    Uns32 pom,pom1,d;

/* Do some tricks to make planets exists */

    if (!ReadGlobalData())
        ErrorExit("Cannot read global data.");
    InitializePlanets();

/* Scan for planets outside wrap rectangle */
     PlanetsNumber =0;
     for (i = 1; i <= PLANET_NR; i++)
      if ((PlanetLocationX(i)<WraparoundRectangle[0])||
          (PlanetLocationX(i)>WraparoundRectangle[2])||
          (PlanetLocationY(i)<WraparoundRectangle[1])||
          (PlanetLocationY(i)>WraparoundRectangle[3]))  XYisPlanet[i]=False;
      else { XYisPlanet[i]=True; PlanetsNumber++; }

/* make BigDistance table */
        for (i=1;i<=PLANET_NR-1;i++)
        if (XYisPlanet[i])
        {
            for (j=i+1;j<=PLANET_NR;j++)
            if (XYisPlanet[j])
                {
                    d= PlanetDistance(i,j);
                    BigDistance[i][j]=d;
                    BigDistance[j][i]=d;
                }
           BigDistance[i][i]=0;
        }
/* Count near, far if needed */

    if (NearFarPlanetCheck)
    {
        for (i=1;i<=PLANET_NR;i++)
        if (XYisPlanet[i])
        {
            GlobalNear[i]=0;
            GlobalFar[i]=0;
        }

        pom =NearSearchRadius*NearSearchRadius;
        pom1=FarSearchRadius*FarSearchRadius;
        for (i=1;i<=PLANET_NR-1;i++)
        if (XYisPlanet[i])
        {
            for (j=i+1;j<=PLANET_NR;j++)
            if (XYisPlanet[j])
                {
                    d= PlanetDist2(i,j);
                    if ( d<=pom)
                       {
                        GlobalNear[i]++;
                        GlobalNear[j]++;
                       }
                    if ( d<=pom1)
                       {
                        GlobalFar [i]++;
                        GlobalFar [j]++;
                       }
                }
        }
    }
}

void  findXY(Uns16 *x, Uns16 *y){

       Uns32 dxx_,dyy_,xxx_,yyy_,X,Y;

       dxx_ = WraparoundRectangle[2]-WraparoundRectangle[0]-1;
       dyy_ = WraparoundRectangle[3]-WraparoundRectangle[1]-1;
        if (UsePGMMaskFile){
                
                X=(WraparoundRectangle[0] +MyRandomRange(dxx_)+1);
                Y=(WraparoundRectangle[1] +MyRandomRange(dyy_)+1);

                yyy_ = Y-WraparoundRectangle[1]-1;
                xxx_ = X-WraparoundRectangle[0]-1;
                
                while (  MyRandomRange(PGMFileD) >=
                PGMFile[ ( (PGMFileY-1-(yyy_)*PGMFileY/dyy_)*PGMFileX +
                           (xxx_)*PGMFileX/dxx_           ) ]){
                X=(WraparoundRectangle[0] +MyRandomRange(dxx_)+1);
                Y=(WraparoundRectangle[1] +MyRandomRange(dyy_)+1);
                
                yyy_ = Y-WraparoundRectangle[1]-1;
                xxx_ = X-WraparoundRectangle[0]-1;
                }
                
                }else{
                        X=(WraparoundRectangle[0] +MyRandomRange(WraparoundRectangle[2]-WraparoundRectangle[0]-1)+1);
                        Y=(WraparoundRectangle[1] +MyRandomRange(WraparoundRectangle[3]-WraparoundRectangle[1]-1)+1);
               }

      *x = (Uns16)X;
      *y = (Uns16)Y;
}

static void doMap(void)
{
       Uns16 Planets[PLANET_NR][3];
       FILE *f;
       int i,j,k,dx,kk;
       Uns16 redo,redoxy,redocount;
       Uns32 xsum,ysum,pom;
       int dx_,dy_,x_,y_,t_;

/* Prepare XYisPlanet array */
    if (PlanetsNumber==PLANET_NR)
    for (i=1;i<=PLANET_NR;i++) XYisPlanet[i]= True;
    else
    {

     if (PlanetsNumber<PLANET_NR/2)
     {
      for (i=1;i<=PLANET_NR;i++) XYisPlanet[i]= False;

      for(i=1;i<=PlanetsNumber;i++)
       {
        j=MyRandomRange(PLANET_NR)+1;
        while (XYisPlanet[j]==True) j=MyRandomRange(PLANET_NR)+1;
        XYisPlanet[j]=True;
       }
     }
     else
     {
      for (i=1;i<=PLANET_NR;i++) XYisPlanet[i]= True;

      for(i=1;i<=PLANET_NR-PlanetsNumber;i++)
       {
        j=MyRandomRange(PLANET_NR)+1;
        while (XYisPlanet[j]==False) j=MyRandomRange(PLANET_NR)+1;
        XYisPlanet[j]=False;
       }
     }

     /* Make sure that planets with given ID for homeworlds
     are generated.  */
     if (ProvideHomeworlds)
      {
       for(i=1;i<=RACE_NR; i++)
        if ((RaceIsPlaying[i])&&(XYisPlanet[Homeworlds_[i]]==False))
        {
          redo= True;
          /* Find assigned planet */
          while (redo)
          {
            j=MyRandomRange(PLANET_NR)+1;
            if (XYisPlanet[j]==True)
            {
              redo = False;
              for(k=1;k<=RACE_NR; k++)
               if ((RaceIsPlaying[k])&&(Homeworlds_[k]==j)) redo=True;
            }
          }// while(redo)

          /* Exchange */
          XYisPlanet[Homeworlds_[i]] = True;
          XYisPlanet[j]              = False;
       }
     } // if (ProvideHomeworlds)
   } // if (PlanetsNumber==PLANET_NR)


/* create map */
    if ((HomeProg)&&(!TestMode)) ConOut("*");
       for (i=0;i<PLANET_NR;i++)
        if (XYisPlanet[i+1])
/* Planet in rectangle */
       {
        findXY(&Planets[i][0],&Planets[i][1]);
        Planets[i][2]=0;
       }
       else
/* Planet outside of rectangle */
       {
        Planets[i][0]= GetOutsideWrapX();
        Planets[i][1]= GetOutsideWrapY();
        Planets[i][2]=0;
       }

/* fixing map   */
       redo=True;
       while(redo)
       {
         redoxy=True;
         while(redoxy)
         {
         redoxy=False;
         if ((HomeProg)&&(!TestMode)) ConOut("?");
 /* check if X,Y are inside or outside rectangle */
         for (i=0;i<PLANET_NR;i++)
         /* check inside */
         if (XYisPlanet[i+1])
         {
               if ( (Planets[i][0]<=WraparoundRectangle[0])||(Planets[i][0]>=WraparoundRectangle[2]) )
               {
                 Planets[i][0]=(Uns16)(WraparoundRectangle[0] +
                     MyRandomRange(WraparoundRectangle[2]-
                                   WraparoundRectangle[0]-1)+1);
                 redoxy=True;
                 redo=True;
                 break;
               }
               if ( (Planets[i][1]<=WraparoundRectangle[1])||(Planets[i][1]>=WraparoundRectangle[3]) )
               {
                 Planets[i][1]=(Uns16)(WraparoundRectangle[1] +
                     MyRandomRange(WraparoundRectangle[3]-
                                   WraparoundRectangle[1]-1)+1);
                 redoxy=True;
                 redo=True;
                 break;
               }
          }
          else
          /* check outside */
         {
               if ( (Planets[i][0]>WraparoundRectangle[0])&&(Planets[i][0]<WraparoundRectangle[2]) )
               {
                 Planets[i][0]= GetOutsideWrapX();
                 redoxy=True;
                 redo=True;
                 break;
               }
               if ( (Planets[i][1]>WraparoundRectangle[1])&&(Planets[i][1]<WraparoundRectangle[3]) )
               {
                 Planets[i][1]= GetOutsideWrapY();
                 redoxy=True;
                 redo=True;
                 break;
               }
          }
         } /* while redoxy out of map */

     if ((HomeProg)&&(!TestMode)) ConOut("%");
         redo=False;
         redoxy=True;
         redocount=0;
         while(redoxy)
         {
         pom=PlanetsMinDistance*PlanetsMinDistance;
         redoxy=False;
         for (i=0;i<PLANET_NR;i++)
         if (XYisPlanet[i+1])
         {
            for (j=i+1;j<PLANET_NR;j++)
            if (XYisPlanet[j+1])
            if (i!=j)
            {

             x_ = abs(Planets[i][0] - Planets[j][0]);
             y_ = abs(Planets[i][1] - Planets[j][1]);
        
             dx_=x_;
             dy_=y_;
        
             if (AllowWraparoundMap) {
             t_= UNI_DX-dx_;
             if (x_>t_) x_=t_;
        
             t_= UNI_DY-dy_;
             if (y_>t_) y_=t_;
             }
             if   ((Uns32)(x_*x_ + y_*y_) <pom)
               {
               redoxy=True;
               redo  =True;
               if (XYisPlanet[i+1])
          /* Planet in rectangle */
                 {
                  findXY(&Planets[i][0],&Planets[i][1]);
                  Planets[i][2]=0;
                 }
                 else
          /* Planet outside of rectangle */
                 {
                  Planets[i][0]= GetOutsideWrapX();
                  Planets[i][1]= GetOutsideWrapY();
                  Planets[i][2]=0;
                 }

               redocount++;
               break;
               }
           if (redoxy) break;
         } /* i!=j */
         } /* for i */
         } /* while redoxy too near */
     redoxy=True;
      while(redoxy)
      {
        redoxy=False;

        /* no need to fix xsum & ysum in test mode */
     if (FixMapSums&&FixMapChecksums&&(!TestMode))
     {
         xsum=0;
         for (i=0;i<PLANET_NR;i++)
           xsum +=Planets[i][0];

     if ((HomeProg)&&(!TestMode)) ConOut("X");
         if (xsum!=0xf3d19)
           {
             redo=True;
             redoxy=True;
             dx = xsum - 0xf3d19;
             if (dx>0)
             {
             while (dx>PLANET_NR){
               dx-=PLANET_NR;
               for (i=0;i<PLANET_NR;i++) Planets[i][0]--;}
             for (i=0;i<dx;i++) Planets[MyRandomRange(PLANET_NR)][0]--;
             }
             else
             {
             while (dx<(-PLANET_NR)){
               dx+=PLANET_NR;
               for (i=0;i<PLANET_NR;i++) Planets[i][0]++;}
             for (i=dx;i<0;i++) Planets[MyRandomRange(PLANET_NR)][0]++;
             }

             for (i=0;i<PLANET_NR;i++)
             if (XYisPlanet[i+1])
             {
              if ((Planets[i][0]<=WraparoundRectangle[0])||(Planets[i][0]>=WraparoundRectangle[2]))
                  Planets[i][0]=(Uns16)(WraparoundRectangle[0] +MyRandomRange(WraparoundRectangle[2]-WraparoundRectangle[0]-1)+1);
             }
             else
              if ((Planets[i][0]>WraparoundRectangle[0])&&(Planets[i][0]<WraparoundRectangle[2]))
                  Planets[i][0]=GetOutsideWrapX();
           } /* xsum */

         ysum=0;
         for (i=0;i<PLANET_NR;i++)
           ysum +=Planets[i][1];

     if ((HomeProg)&&(!TestMode)) ConOut("Y");
         if (ysum!=0xf4c89)
           {
             redo=True;
             redoxy=True;
             dx = ysum - 0xf4c89;
             if (dx>0)
             {
             while (dx>PLANET_NR){
               dx-=PLANET_NR;
               for (i=0;i<PLANET_NR;i++) Planets[i][1]--;}
             for (i=0;i<dx;i++) Planets[MyRandomRange(PLANET_NR)][1]--;
             }
             else
             {
             while (dx<(-PLANET_NR)){
               dx+=PLANET_NR;
               for (i=0;i<PLANET_NR;i++) Planets[i][1]++;}
             for (i=dx;i<0;i++) Planets[MyRandomRange(PLANET_NR)][1]++;
             }
             for (i=0;i<PLANET_NR;i++)
             if (XYisPlanet[i+1])
             {
              if ((Planets[i][1]<=WraparoundRectangle[1])||(Planets[i][1]>=WraparoundRectangle[3]))
                  Planets[i][1]=(Uns16)(WraparoundRectangle[1] +MyRandomRange(WraparoundRectangle[3]-WraparoundRectangle[1]-1)+1);
             }
             else
              if ((Planets[i][1]>WraparoundRectangle[1])&&(Planets[i][1]<WraparoundRectangle[3]))
                  Planets[i][1]=GetOutsideWrapY();
           } /* ysum */
      } /* sum checking and fixing */
     } /* redoxy xsum, ysum */
    } /* while redo */
    if ((HomeProg)&&(!TestMode)) ConOut("\n\r");

/* writing to file */
       f=OpenOutputFile(mapfilename,GAME_DIR_ONLY);
       if (f==NULL)  ErrorExit("Cannot write map file %s. Exiting.\n",mapfilename);
       DOSWrite16((Uns16 *)Planets,PLANET_NR*3,f);
       if (f!=NULL) fclose(f);
/* writing to file for THost compatibility */
       f=OpenOutputFile(THostmapfilename,GAME_DIR_ONLY);
       if (f==NULL)  ErrorExit("Cannot write map file %s. Exiting.\n",THostmapfilename);
       DOSWrite16((Uns16 *)Planets,PLANET_NR*3,f);
       if (f!=NULL) fclose(f);

}

static void doWormhole(void)
{
   FILE *f;
   time_t t;

   int i,j;
   Uns16 sx,sy,ex,ey;
   int wm,instb;
   Uns16 msx,msy,mex,mey;
   Boolean WormCanBe;
   Uns32 WormCount=0;
   Uns16 sx_[MAXWORMHOLES];
   Uns16 sy_[MAXWORMHOLES];
   Uns16 ex_[MAXWORMHOLES];
   Uns16 ey_[MAXWORMHOLES];

   f=OpenOutputFile(wormholename,GAME_DIR_ONLY|TEXT_MODE);
   if (f==NULL) ErrorExit("Cannot open wormhole file %s. Exiting.\n",wormholename);
   fprintf(f,"#\n# Wormhole file generated by AMASTER v%d.%d%c\n",pMajor,pMinor,pLetter);
   t=time(NULL);
   fprintf(f,"# %s#\n",ctime(&t) );

   for(i=0;i<WormholeNumber;i++)
   {
 /*  wormhole start/end */
     WormCanBe=False;
     while (!WormCanBe)
     {
     sx = MyRandomRange(WormholeStartRange[2]-WormholeStartRange[0]+1)+WormholeStartRange[0];
     sy = MyRandomRange(WormholeStartRange[3]-WormholeStartRange[1]+1)+WormholeStartRange[1];

     sx_[i]=sx;
     sy_[i]=sy;

     WormCount++;
     if (WormCount>MaxWormholesCounter)
       ErrorExit("Cannot create wormholes. Too many iterations.");

     WormCanBe=True;

     for (j=0;j<i;j++)
       if (DistWrap2(sx,sy,sx_[j],sy_[j])<MinWormholesDistance*MinWormholesDistance)
          WormCanBe=False;

     for (j=0;j<i;j++)
       if (DistWrap2(sx,sy,ex_[j],ey_[j])<MinWormholesDistance*MinWormholesDistance)
          WormCanBe=False;

     if (NoWormholesNearHomeworlds  == True)
      {
      for (j=1;j<=RACE_NR;j++)
       {
        if ((RaceIsPlaying[j])&&(OwnedPlanets[j]>0))
         if (DistWrap2(sx,sy,PlanetLocationX(Homeworlds[j]),PlanetLocationY(Homeworlds[j]))<=MinWormHomeDistance*MinWormHomeDistance)
          WormCanBe=False;
       }
      }

     if (NoWormholesNearPlanets == True)
      {
      for (j=1;j<=PLANET_NR;j++)
      if (XYisPlanet[j])
       {
       if (IsPlanetExist(j))
        if (DistWrap2(sx,sy,PlanetLocationX(j),PlanetLocationY(j))<=MinWormPlanetDistance*MinWormPlanetDistance)
         WormCanBe=False;
       }
      }

     } /* while, sx & sy */

     WormCanBe=False;
     while (!WormCanBe)
     {
     ex = MyRandomRange(WormholeEndRange[2]-WormholeEndRange[0]+1)+WormholeEndRange[0];
     ey = MyRandomRange(WormholeEndRange[3]-WormholeEndRange[1]+1)+WormholeEndRange[1];

     ex_[i] = ex;
     ey_[i] = ey;

     WormCount++;
     if (WormCount>MaxWormholesCounter)
       ErrorExit("Cannot create wormholes. Too many iterations.");
     WormCanBe=True;

     for (j=0;j<=i;j++) /* check last sx,sy too */
       if (DistWrap2(ex,ey,sx_[j],sy_[j])<MinWormholesDistance*MinWormholesDistance)
          WormCanBe=False;

     for (j=0;j<i;j++)
       if (DistWrap2(ex,ey,ex_[j],ey_[j])<MinWormholesDistance*MinWormholesDistance)
          WormCanBe=False;


     if (NoWormholesNearHomeworlds  == True)
     {
     for (j=1;j<=RACE_NR;j++)
     {
      if ((RaceIsPlaying[j])&&(OwnedPlanets[j]>0))
       if (DistWrap2(ex,ey,PlanetLocationX(Homeworlds[j]),PlanetLocationY(Homeworlds[j]))<=MinWormHomeDistance*MinWormHomeDistance)
        WormCanBe=False;
     }
     }

     if (NoWormholesNearPlanets == True)
      {
      for (j=1;j<=PLANET_NR;j++)
      if (XYisPlanet[j])
       {
       if (IsPlanetExist(j))
        if (DistWrap2(ex,ey,PlanetLocationX(j),PlanetLocationY(j))<=MinWormPlanetDistance*MinWormPlanetDistance)
         WormCanBe=False;
       }
      }

    /* Wormhole length */
    if (DistWrap2(ex,ey,sx,sy)<=MinWormholeLength*MinWormholeLength)
         WormCanBe=False;

    } /* while, ex & ey */

/* wormhole mass */
     wm = MyRandomRange(WormholeMassRange[1]-WormholeMassRange[0]+1)+WormholeMassRange[0];
/* unidirectional wormholes have mass below zero */
     if (MyRandomRange(100)<WormholeUniDirChance) wm=0-wm;
/* instability */
     instb = MyRandomRange(WormholeInstabilityRange[1]-WormholeInstabilityRange[0]+1)+WormholeInstabilityRange[0];
/* movement of start */
     if (MyRandomRange(100)<WormholeStartMoveChance)
     {
       msx = MyRandomRange(WormholeStartRange[2]-WormholeStartRange[0]+1)+WormholeStartRange[0];
       msy = MyRandomRange(WormholeStartRange[3]-WormholeStartRange[1]+1)+WormholeStartRange[1];
     }
     else
     {
       msx = sx;
       msy = sy;
     }
/* movement of end */
     if (MyRandomRange(100)<WormholeEndMoveChance)
     {
       mex = MyRandomRange(WormholeStartRange[2]-WormholeStartRange[0]+1)+WormholeStartRange[0];
       mey = MyRandomRange(WormholeStartRange[3]-WormholeStartRange[1]+1)+WormholeStartRange[1];
     }
     else
     {
       mex = ex;
       mey = ey;
     }
     fprintf(f,"%6d %6d %6d %6d ",sx,sy,ex,ey);
     fprintf(f,"%7d %5.1f ",wm,(float)instb);
     fprintf(f,"%6d %6d %6d %6d\n",msx,msy,mex,mey);
     }

   if (f!=NULL) fclose(f);
}

static void     doPlanetRandomize(void)
{
     Uns16   planet;
     Uns16   cargo;
     Uns16   t;
     char    FC[4];
     int     sum;
     int     res;
     int     i,j;

     Uns32   Cash, nat;
     double  NatTax,NatGovm,NativePopulation;
     Uns16   NatType;
     double  MineRate;
     double  MineTurns;

     for (planet = 1; planet <= PLANET_NR; planet++)
     if (XYisPlanet[planet])
     {
          if (!IsPlanetExist(planet))
               continue;

 /* Start setting attributes */
          PutPlanetOwner(planet, NoOwner);

          PutPlanetCargo(planet, COLONISTS, 0UL);
          PutPlanetCargo(planet, SUPPLIES, 0U);
          PutPlanetCargo(planet, CREDITS, 0U);

          sprintf(FC, "%03lu", MyRandomRange(1000));       /* random friendly code */
          PutPlanetFC(planet, FC);

          PutPlanetMines(planet, 0);
          PutPlanetFactories(planet, 0);
          PutPlanetDefense(planet, 0);

 /* Temperature for standard planets */

     if (BioSupport)
        {
          do {
          t = PlanetsTempRange[0] +
              MyRandomRange(PlanetsTempRange[1] - PlanetsTempRange[0]+1);
          } while ( MyRandomRange(101) > sin (3.14159*( t - PlanetsTempRange[0])/
           (PlanetsTempRange[1] - PlanetsTempRange[0]))*BioSupportLevel + (100.0-BioSupportLevel) );
          PutPlanetTemp(planet, t);
         }
     else
          PutPlanetTemp(planet, MyRandomRange(101));

          for (cargo = NEUTRONIUM; cargo <= MOLYBDENUM; cargo++)
          {
               PutPlanetCargo(planet, cargo, PlanetSurfaceRanges[cargo] +
                              MyRandomRange(PlanetSurfaceRanges[cargo + 4] -
                                          PlanetSurfaceRanges[cargo]+1)   );

               if (MyRandomRange(100) < PlanetCoreUsualFrequency[cargo])
                    PutPlanetCore(planet, cargo, PlanetCoreRangesUsual[cargo] +
                                  MyRandomRange(PlanetCoreRangesUsual[cargo + 4] -
                                              PlanetCoreRangesUsual[cargo]+1)  );
               else
                    PutPlanetCore(planet, cargo, PlanetCoreRangesAlternate[cargo] +
                                  MyRandomRange(PlanetCoreRangesAlternate[cargo + 4] -
                                              PlanetCoreRangesAlternate[cargo]+1)  );


               PutPlanetDensity(planet, cargo,
                                PlanetDensityRanges[cargo] +
                                MyRandomRange(PlanetDensityRanges[cargo + 4] -
                                            PlanetDensityRanges[cargo]+1)  );
          }

          PutPlanetColTax(planet, 0);
          PutPlanetNatTax(planet, 0);
          PutPlanetColHappy(planet, DefaultColonistHappy);
          PutPlanetNatHappy(planet, DefaultNativesHappy);

 /* Decide if this planet is to have natives. */
          if (MyRandomRange(100) < NativesOnPlanetFrequency)
          {
               sum = 0;
               for (i = 1; i < 10; i++)
                    sum += NativeTypeFrequencies[i];
               res = MyRandomRange(sum);
               sum = 0;
               for (i = 1; i < 10; i++)
               {
                    sum += NativeTypeFrequencies[i];
                    if (sum > res)
                         break;
               }
               PutPlanetNativeType(planet, i);

               nat = (NativeRange[0] +  MyRandomRange(NativeRange[1] - NativeRange[0]+1)) * 1000UL;
               if (AdjustPopulations)
                 nat = min (nat, MaxNativesOnPlanet(i,PlanetTemp(planet)));
               PutPlanetNativePopulation(planet,nat);

               if (nat!=0)
               {
               sum = 0;
               for (i = 1; i < 10; i++)
                    sum += NativeGovFrequencies[i];
               res = MyRandomRange(sum);
               sum = 0;
               for (i = 1; i < 10; i++)
               {
                    sum += NativeGovFrequencies[i];
                    if (sum > res)
                         break;
               }

               PutPlanetNatGovm(planet, i);
               }
               else
               PutPlanetNativeType(planet, NoNatives); /* after adjustment */

          }
          else
             {
               PutPlanetNativePopulation(planet, 0);
               PutPlanetNativeType(planet, NoNatives);
               PutPlanetNatGovm(planet,NoGovm);
               PutPlanetNatTax  (planet,  0);
               PutPlanetNatHappy(planet, DefaultNativesHappy);
             }
     } /* planet 1..500 */

/* Natives cash for each planet, rate=100.0 */
     for (j=1;j<=PLANET_NR;j++)
     if (XYisPlanet[j])
       GlobalNatCash[j]=0;

     if (NativeCashCheck)
     {
       for (j=1;j<=PLANET_NR;j++)
         if (XYisPlanet[j])
          {
           if ((NatType=PlanetNatType(j))!=NoNatives)
           {
             NatGovm          = PlanetNatGovm(j);
             NativePopulation = PlanetNativePopulation(j);
             NatTax = (5.0 + NatGovm/2.0 - sqrt ( NativePopulation/10000.0/100.0))/0.85;
             if (NatType==Avian) NatTax+=10.0/0.85;
             Cash =(Uns32) ((NativePopulation/100.0*NatGovm*NatTax+2500.0)/5000.0);
             if (NatType==Insectoid) Cash*=2;
             if (NatType==Amorphous) Cash=0;
             GlobalNatCash[j]=(Uns32)(((float)Cash*100.0+50.0)/100.0);
           }
         }
      }  /* check  NativeCashCheck */

     if (MineCheck)
     {
       for (j=1;j<=PLANET_NR;j++)
         if (XYisPlanet[j])
          {
              NatType  = PlanetNatType(j);
           /* Tritanium */
              MineRate = 200.0 * 100.0 * PlanetDensity(j,TRITANIUM)/100.0/100.0;
              if (NatType==Reptilian) MineRate*=2.0;
              MineTurns= (double)PlanetCore(j,TRITANIUM)/MineRate;
              if (MineTurns>MaxMineTurns) MineTurns=MaxMineTurns;
              GlobalMineT[j] = MineTurns*MineRate;

           /* Duranium */
              MineRate = 200.0 * 100.0 * PlanetDensity(j,DURANIUM)/100.0/100.0;
              if (NatType==Reptilian) MineRate*=2.0;
              MineTurns= (double)PlanetCore(j,DURANIUM)/MineRate;
              if (MineTurns>MaxMineTurns) MineTurns=MaxMineTurns;
              GlobalMineD[j] = MineTurns*MineRate;

           /* Molybdenium */
              MineRate = 200.0 * 100.0 * PlanetDensity(j,MOLYBDENUM)/100.0/100.0;
              if (NatType==Reptilian) MineRate*=2.0;
              MineTurns= (double)PlanetCore(j,MOLYBDENUM)/MineRate;
              if (MineTurns>MaxMineTurns) MineTurns=MaxMineTurns;
              GlobalMineM[j] = MineTurns*MineRate;
         }

       for (j=1;j<=PLANET_NR;j++)
       if (XYisPlanet[j])
       {
         GlobalMineT[j] = GlobalMineT[j]/MaxMineTurns;
         GlobalMineD[j] = GlobalMineD[j]/MaxMineTurns;
         GlobalMineM[j] = GlobalMineM[j]/MaxMineTurns;
       }

      }  /* check  MineCheck */

}

static void     doHomeworlds(void)
{
     int    i;
     char   FC[4];

for (i=1 ; i <=RACE_NR ; i++)
{
if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0))
{
   Uns16 cplan = Homeworlds[i];

   PutPlanetOwner(cplan, i);

   sprintf(FC, "%03lu", MyRandomRange(1000));       /* random friendly code */
   PutPlanetFC(cplan, FC);

   PutPlanetMines    (cplan, HomeworldMines    [i]);
   PutPlanetFactories(cplan, HomeworldFactories[i]);
   PutPlanetDefense  (cplan, HomeworldDefence  [i]);

   PutPlanetCargo(cplan, NEUTRONIUM,  HomeworldSurfaceN[i]);
   PutPlanetCargo(cplan, TRITANIUM,   HomeworldSurfaceT[i]);
   PutPlanetCargo(cplan, DURANIUM,    HomeworldSurfaceD[i]);
   PutPlanetCargo(cplan, MOLYBDENUM,  HomeworldSurfaceM[i]);

   PutPlanetCargo(cplan, COLONISTS, (HomeworldClans   [i])*100UL);
   PutPlanetCargo(cplan, SUPPLIES,   HomeworldSupplies[i]);
   PutPlanetCargo(cplan, CREDITS,    HomeworldCash    [i]);

   PutPlanetCore(cplan, NEUTRONIUM,  HomeworldCoreN[i]);
   PutPlanetCore(cplan, TRITANIUM,   HomeworldCoreT[i]);
   PutPlanetCore(cplan, DURANIUM,    HomeworldCoreD[i]);
   PutPlanetCore(cplan, MOLYBDENUM,  HomeworldCoreM[i]);

   PutPlanetDensity(cplan, NEUTRONIUM, HomeworldDensityN[i]);
   PutPlanetDensity(cplan, TRITANIUM,  HomeworldDensityT[i]);
   PutPlanetDensity(cplan, DURANIUM,   HomeworldDensityD[i]);
   PutPlanetDensity(cplan, MOLYBDENUM, HomeworldDensityM[i]);

   PutPlanetColTax  (cplan, HomeworldColonistTax  [i]);
   PutPlanetColHappy(cplan, HomeworldColonistHappy[i]);

/* No natives on Homeworld on start */
   PutPlanetNativePopulation(cplan, 0);
   PutPlanetNatType (cplan, NoNatives);
   PutPlanetNatGovm (cplan, NoGovm);
   PutPlanetNatTax  (cplan,  0);
   PutPlanetNatHappy(cplan, DefaultNativesHappy);
   
 /* Temperature of homeworld */
   if ((PlayerRace[i]==7)&&(CrystalsPreferDeserts))
        PutPlanetTemp(cplan, 100U);
   else PutPlanetTemp(cplan, 50U);
}
}
}


Boolean  SearchHomeworlds(void)
{
     int    i = 1;
     int    ltest;
     Uns32  gtest;
     Uns16  PID;
     int    j;
     int    fl=1;
     Uns32 pom;
     Uns32 pomMax;
     
     ltest=0;
     gtest=0;
     pom=HomeworldsRadius*HomeworldsRadius;
     pomMax=HomeworldsMaxRadius*HomeworldsMaxRadius;
     while ((i <=RACE_NR) && (gtest <=MaxHWCounter))
     {
          if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0))
          {
               for (ltest = 1; ltest <= MAXHOMETRY; ltest++, gtest++)
               {
                    PID = 1 + MyRandomRange(PLANET_NR);
                    if (!(CanBeHW[PID])) continue;
                    fl = 1;
                    Homeworlds[i]=PID;
		    if (i>1) {
		      int found = 0;
		      for (j = 1; j < i; j++) {
                        if (RaceIsPlaying[j])
                        {
                          if (PlanetDist2(PID, Homeworlds[j]) < pom) fl = 0;
                          if (fl==0) break;
                        }
		      }
		      if (fl) for (j = 1; j < i; j++) {
                        if (RaceIsPlaying[j])
                        {
			  if (PlanetDist2(PID, Homeworlds[j]) < pomMax) {
			    found = 1;
			    break;
			  }
                        }
		      }
		      if (!found) fl = 0;

		    }
                    if (fl==1) break;
               } /* for, gtest */
               if (fl==1) i++;
               else {
                      for (j=1;j<=RACE_NR;j++) Homeworlds[j]=0;
                      i=1;
                     }
          }  /* race is playing */
          else{
               Homeworlds[i]=0;
               i++;
          }
     }

     if (gtest >MaxHWCounter) return False;
     else                     return True;
}

static void searchPlanetsBases(void)
{
               int     i,k,j;
               Uns16   pID,lp,CID,bID,tmp;
               int     dist,bdist;
               Boolean IsOwned[PLANET_NR+1];
               Uns32   max,max_i,d,trys;
               int     b,p,go,r;
               Uns16   planet;
               double  prob;
               Uns16   allowed[MAXHOMEPLANETS+1];

/* Init IsOwned array */

  for(i=1;i<=PLANET_NR;i++)
  if (XYisPlanet[i])
   IsOwned[i]=0;

  for (i=1 ; i <=RACE_NR ; i++)
     if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0))
      IsOwned[Homeworlds[i]]=1;

/* Finding the most closest planets to homeworlds */
  lp=0;

  for (k=1 ; k <= MAXHOMEPLANETS; k++)
  {
  for (i=1 ; i <=RACE_NR ; i++)
  {
     if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0))
     {
      CID=Homeworlds[i];
      if (k < OwnedPlanets[i] )
      {
        bdist=10000000;
        bID=0;

        for (pID=1; pID<=PLANET_NR ; pID++)
        if (XYisPlanet[pID])
        {
          if (!(IsOwned[pID]))
          {
            if ( (dist=PlanetDist2(pID,CID)) < bdist )
            {
            bdist=dist;
            bID=pID;
            }
          }
        }/* for PLANET_NR */

        if (bID==0)
        {
          Warning("HomePlanet #%d for race %d will be not assigned.",k,i);
          Warning("All %d planets already assigned.",PlanetsNumber);
        }
        else
        {
          Planets[i][k]=bID;
          if (lp==0) lp=bID;
          IsOwned[bID] =1;
        }
       }/* owned planets */
      } /* race is playing */
     } /* races */
    } /* homeplanets */

/* make other bases */

/* copy Planets to Bases */

for (j=1 ; j <=RACE_NR ; j++)
 if ((RaceIsPlaying[j])&&(OwnedPlanets[j]>0))
 {
  /* one cannot have more bases than planets */
  if (OwnedBases[j]>OwnedPlanets[j]) OwnedBases[j]=OwnedPlanets[j];

  for (k=1 ; k < 100 ; k++)
  {
    planet=Planets[j][k];

    if ( (XYisPlanet[planet]) && (IsPlanetExist(planet)) && (OwnedBases[j]>k) )
       Bases[j][k] = planet;
  }
 }

/* move bases when needed */
for (j=1 ; j <=RACE_NR ; j++)
 if ((RaceIsPlaying[j])&&
     (OwnedPlanets[j]>OwnedBases[j])&&
     (OwnedBases[j]>1)&&(OwnedPlanets[j]>0))
 {
 /* find the most distant player planet */
  max=0;
  max_i=0;
  for (k=1;k<OwnedPlanets[j];k++)
   if ((d=PlanetDist2(Homeworlds[j],Planets[j][k]))>max)
   {
      max=d;
      max_i=k;
   }
 /* limit planets due to BaseHopsLimit */
  for (k=1;k<OwnedPlanets[j];k++)
   if (PlanetDist2(Homeworlds[j],Planets[j][k])>(Uns32)BaseHopsLimit[1]*(Uns32)BaseHopsLimit[1]*max/10000)
     allowed[k]=False;
   else
     {
      if (PlanetDist2(Homeworlds[j],Planets[j][k])<(Uns32)BaseHopsLimit[0]*(Uns32)BaseHopsLimit[0]*max/10000)
        allowed[k]=False;
      else
        allowed[k]=True;
     }
  for (k=1 ; k < BaseHopsNumber ; k++)
  {
    /* find base */
    b =1+MyRandomRange(OwnedBases[j]-1);
    go=True;
    trys=0;

    while ((go)&&(trys<500))
    {
      go=False;
      p =1+MyRandomRange(OwnedPlanets[j]-1);
      if (!allowed[p]) { go=True; trys++; }
      for (r=1;r<OwnedBases[j];r++)
       if (Bases[j][r]==Planets[j][p]) { go=True; trys++; break; }
    }

    if (trys<500)
    {
    /* try to make probablistic jump only when new planet found */
    prob = exp ( - sqrt(PlanetDist2(Bases[j][b],Planets[j][p])) /
                    (double)BaseHopsFactor )*10000.0;

    if (MyRandomRange(10000) < prob)
      Bases[j][b] = Planets[j][p];
    }

  } /* k<basehops */

  if (BindPlanetsToBases)
  {
  /* sortbases */

    for (i=1;i<OwnedBases[j];i++)
     for (k=i+1;k<OwnedBases[j];k++)
      if (PlanetDist2(Homeworlds[j],Bases[j][k]) <
          PlanetDist2(Homeworlds[j],Bases[j][i]))
          {
            tmp = Bases[j][k];
            Bases[j][k] = Bases[j][i];
            Bases[j][i] = tmp;
          }

  /* bind */

    for (i=1;i<OwnedBases[j];i++)
     for (k=i+1;k<OwnedPlanets[j];k++)
      if (Bases[j][i] == Planets[j][k] )
          {
            tmp = Planets[j][k];
            Planets[j][k] = Planets[j][i];
            Planets[j][i] = tmp;
          }

    /* sort rest of the planets */
    for (i=1;i<OwnedPlanets[j];i++)
    {
       allowed[i]=True;

      for (k=1;k<OwnedBases[j];k++)
      if (Bases[j][k]==Planets[j][i]) allowed[i]=False;
    }

    for (i=1;i<OwnedPlanets[j];i++)
    if (allowed[i])
     for (k=i+1;k<OwnedPlanets[j];k++)
      if (allowed[i])
      if (PlanetDist2(Homeworlds[j],Planets[j][k]) <
          PlanetDist2(Homeworlds[j],Planets[j][i]))
          {
            tmp = Planets[j][k];
            Planets[j][k] = Planets[j][i];
            Planets[j][i] = tmp;
          }

  }


 } /* race is playing AND OwnedPlanets>OwnedBases */

}


static void doHomePlanets(void)
{
               int     j,k,i,t;
               int     sum;
               int     res;
               Uns32   nat;
               Uns16   planet,planetlp;
               int     Typ;
               Uns16   CopyTo[PLANET_NR+1],foundID;
               Boolean found;


for (j=1 ; j <=RACE_NR ; j++)
 if (RaceIsPlaying[j])
  for (k=1 ; k <= MAXHOMEPLANETS ; k++)
    {
    planet=Planets[j][k];

    if ((IsPlanetExist(planet))&&(XYisPlanet[planet]))
      {
        PutPlanetOwner    (planet, j);
        PutPlanetMines    (planet, HomePlanet[k-1][1]);
        PutPlanetFactories(planet, HomePlanet[k-1][2]);
        PutPlanetDefense  (planet, HomePlanet[k-1][3]);
        PutPlanetColHappy (planet, HomePlanet[k-1][6]);
        PutPlanetColTax   (planet, HomePlanet[k-1][7]);
        PutPlanetCargo    (planet, COLONISTS, HomePlanet[k-1][0]*100);
        PutPlanetCargo    (planet, SUPPLIES , HomePlanet[k-1][5]);
        PutPlanetCargo    (planet, CREDITS  , HomePlanet[k-1][4]);

    /* PW Biosupport, version 3.5 */
        if (BioSupport)
        {
           do {
           t = OwnedPlanetsTempRange[0] +
               MyRandomRange(OwnedPlanetsTempRange[1] - OwnedPlanetsTempRange[0]+1);
           } while ( MyRandomRange(101) > sin (3.14159*( t - OwnedPlanetsTempRange[0])/
            (OwnedPlanetsTempRange[1] - OwnedPlanetsTempRange[0]))*BioSupportLevel + (100.0-BioSupportLevel) );
           PutPlanetTemp(planet, t);
        }
    /* !PW Biosupport*/

        Typ=PlanetsNat[k-1][0];

        if (Typ==-1)
        {
        /* find randomly natives type */

              sum = 0;
              for (i = 1; i < 10; i++)
                   sum += NativeTypeFrequencies[i];
              res = MyRandomRange(sum);
              sum = 0;
              for (i = 1; i < 10; i++)
              {
                   sum += NativeTypeFrequencies[i];
                   if (sum > res)
                        break;
              }
              Typ = i;
        }

        if (Typ>0)
        {
        /* natives number */

           if (PlanetsNat[k-1][2]==-1)
              nat = (NativeRange[0] +
                      MyRandomRange(NativeRange[1] - NativeRange[0]+1)) * 1000UL;
           else nat = PlanetsNat[k-1][2] * 100UL;
           if (AdjustPopulations)
             nat = min (nat, MaxNativesOnPlanet(Typ,PlanetTemp(planet)));

           PutPlanetNativePopulation(planet,nat);

           if (PlanetNativePopulation(planet)>0)
           {
              PutPlanetNativeType(planet, Typ);

        /* natives goverment */
              if (PlanetsNat[k-1][1]==-1)
              {
              sum = 0;
              for (i = 1; i < 10; i++)
                   sum += NativeGovFrequencies[i];
              res = MyRandomRange(sum);
              sum = 0;
              for (i = 1; i < 10; i++)
              {
                   sum += NativeGovFrequencies[i];
                   if (sum > res)
                        break;
              }
              } /* -1 */
              else
              i = PlanetsNat[k-1][1];

              PutPlanetNatGovm(planet, i);

        /* natives happy */
              if (PlanetsNat[k-1][3]==-1)
                 i = DefaultNativesHappy;
              else
                 i = PlanetsNat[k-1][3];

              PutPlanetNatHappy(planet, i);

        /* natives tax */
              if (PlanetsNat[k-1][4]==-1)
                 i = 0;
              else
                 i = PlanetsNat[k-1][4];

              PutPlanetNatTax(planet, i);

           } /* natives pop > 0 */
        } /* put natives on planets */

        /* Delete natives on planet */
        if (Typ==0)
        {
          PutPlanetNativePopulation(planet, 0);
          PutPlanetNativeType      (planet, NoNatives);
          PutPlanetNatGovm         (planet, NoGovm);
          PutPlanetNatTax          (planet, 0);
          PutPlanetNatHappy        (planet, DefaultNativesHappy);
        }

        /* Delete Amorphous when requested */
        if ((NoAmorphousOnHomePlanets)&&
            (PlanetNatType(planet)==Amorphous))
        {
          PutPlanetNativePopulation(planet, 0);
          PutPlanetNativeType      (planet, NoNatives);
          PutPlanetNatGovm         (planet, NoGovm);
          PutPlanetNatTax          (planet, 0);
          PutPlanetNatHappy        (planet, DefaultNativesHappy);
        }

      } /* Planet exists */
    } /* for k=1..MAXHOMEPLANETS */

/* Prepare CopyTo array */
   for (k=1 ; k <= PLANET_NR; k++) CopyTo[k]=0;

/* AllOwnedPlanetsTheSame */
   if (AllOwnedPlanetsTheSame)
   {
     for (k=1 ; k <= MAXHOMEPLANETS; k++)
     {
     found=False;
     for (i=1 ; i <=RACE_NR ; i++)
     {
      if ((Planets[i][k]!=0)&&(found))
          CopyTo[Planets[i][k]]= foundID;

      if ((Planets[i][k]!=0)&&(!found))
        {
           found   = True;
           foundID = Planets[i][k];
        }
      } /* races */
     } /* home planets */
    } /* allownedthesame */


/* AllPlayerPlanetsTheSame */
   if (AllPlayerPlanetsTheSame)
   {
     for (i=1 ; i <=RACE_NR ; i++)
     {
     found=False;
     for (k=1 ; k <= MAXHOMEPLANETS; k++)
     {
      if ((Planets[i][k]!=0)&&(found))
          CopyTo[Planets[i][k]]= foundID;

      if ((Planets[i][k]!=0)&&(!found))
        {
           found   = True;
           foundID = Planets[i][k];
        }
      } /* home planets */
     } /* races */
    } /* allownedthesame */

/* AllPlayerPlanetsTheSame and AllOwnedPlanetsTheSame */
   if ((AllPlayerPlanetsTheSame)&&(AllOwnedPlanetsTheSame))
   {
     found=False;
     for (i=1 ; i <=RACE_NR ; i++)
     {
     for (k=1 ; k <= MAXHOMEPLANETS; k++)
     {
      if ((Planets[i][k]!=0)&&(found))
          CopyTo[Planets[i][k]]= foundID;

      if ((Planets[i][k]!=0)&&(!found))
        {
           found   = True;
           foundID = Planets[i][k];
        }
      } /* home planets */
     } /* races */
    } /* allownedthesame */


    if ((AllOwnedPlanetsTheSame)||(AllPlayerPlanetsTheSame))
    {
       for (k=1 ; k <= PLANET_NR; k++)
       if (CopyTo[k]!=0)
       {
          planet=k;
          planetlp=CopyTo[k];
          if (IsPlanetExist(planetlp))
          {
           PutPlanetTemp(planet,PlanetTemp(planetlp) );

           PutPlanetCargo(planet, NEUTRONIUM, PlanetCargo(planetlp, NEUTRONIUM));
           PutPlanetCargo(planet, TRITANIUM,  PlanetCargo(planetlp, TRITANIUM));
           PutPlanetCargo(planet, DURANIUM,   PlanetCargo(planetlp, DURANIUM));
           PutPlanetCargo(planet, MOLYBDENUM, PlanetCargo(planetlp, MOLYBDENUM));

           PutPlanetCore(planet, NEUTRONIUM,  PlanetCore(planetlp, NEUTRONIUM));
           PutPlanetCore(planet, TRITANIUM,   PlanetCore(planetlp, TRITANIUM));
           PutPlanetCore(planet, DURANIUM,    PlanetCore(planetlp, DURANIUM));
           PutPlanetCore(planet, MOLYBDENUM,  PlanetCore(planetlp, MOLYBDENUM));

           PutPlanetDensity(planet, NEUTRONIUM, PlanetDensity(planetlp, NEUTRONIUM));
           PutPlanetDensity(planet, TRITANIUM,  PlanetDensity(planetlp, TRITANIUM));
           PutPlanetDensity(planet, DURANIUM,   PlanetDensity(planetlp, DURANIUM));
           PutPlanetDensity(planet, MOLYBDENUM, PlanetDensity(planetlp, MOLYBDENUM));

           PutPlanetNativePopulation(planet, PlanetNativePopulation(planetlp));
           PutPlanetNatGovm         (planet, PlanetNatGovm(planetlp));
           PutPlanetNativeType      (planet, PlanetNatType(planetlp));
           PutPlanetNatTax          (planet, PlanetNatTax(planetlp));
           PutPlanetNatHappy        (planet, PlanetNatHappy(planetlp));

           PutPlanetMines    (planet, PlanetMines          (planetlp));
           PutPlanetFactories(planet, PlanetFactories      (planetlp));
           PutPlanetDefense  (planet, PlanetDefense        (planetlp));
           PutPlanetColHappy (planet, PlanetColHappy       (planetlp));
           PutPlanetColTax   (planet, PlanetColTax         (planetlp));
           PutPlanetCargo    (planet, COLONISTS,PlanetCargo(planetlp,COLONISTS));
           PutPlanetCargo    (planet, SUPPLIES ,PlanetCargo(planetlp,SUPPLIES));
           PutPlanetCargo    (planet, CREDITS  ,PlanetCargo(planetlp,CREDITS ));
           } /* planet exists */
       } /* copyto!= 0 */
    } /*  if  AllOwnedPlanetsTheSame AND AllPlayerPlanetsTheSame */
}

static void     doBases(void)
{
int j,k;
Uns16 planet;

/* make homeworld base */

for (j=1 ; j <=RACE_NR ; j++)
 if ((RaceIsPlaying[j])&&(OwnedPlanets[j]>0))
{
planet=Homeworlds[j];
if ( (XYisPlanet[planet])&&(IsPlanetExist(planet))&&(OwnedBases[j]>0) )
 {
    CreateBase(planet);  /* automatically sets owner from planet */
    PutBaseDefense(planet,BaseFreeDefence[j] );
    PutBaseFighters(planet,BaseFreeFighters[j] );
    PutBaseOrder(planet, NoBaseMission);
    PutBaseTech(planet, ENGINE_TECH, StartingEngineTech[j]);
    PutBaseTech(planet, HULL_TECH,   StartingHullTech[j]);
    PutBaseTech(planet, BEAM_TECH,   StartingBeamTech[j]);
    PutBaseTech(planet, TORP_TECH,   StartingTubeTech[j]);

    if (BaseFreeHulls[j])
    {
    PutBaseHulls(planet, 1, 1);   /* One free ship in slot 1 */
    PutBaseHulls(planet, 2, 1);   /* One free ship in slot 2 */
    }

    if (BaseFreeEngines[j])
    {
    PutBaseEngines(planet, 1, 4); /* Four free StarDrive 1 engines */
    PutBaseEngines(planet, 3, 2); /* Two free StarDrive 3 engines */
    }

    if (BaseFreeBeams[j])
    {
    PutBaseBeams(planet, 2, 8);   /* Eight free X-Rays */
    }

    if (BaseFreeTorps[j])
    {
    PutBaseTubes(planet, 2, 3);   /* Three free Proton torpedo tubes */
    PutBaseTorps(planet, 2, 20);  /* 20 free Proton torpedoes */
    }
  }

}

/* make bases */

for (j=1 ; j <=RACE_NR ; j++)
 if (RaceIsPlaying[j])
  for (k=1 ; k < 100 ; k++)
 {
 planet=Bases[j][k];

 if ( (XYisPlanet[planet])&&(IsPlanetExist(planet)) && (OwnedBases[j]>k) )
  {
     CreateBase(planet);  /* automatically sets owner from planet */

     if (AllBasesTheSame)
     {
     PutBaseDefense(planet, BaseFreeDefence[j]);
     PutBaseFighters(planet, BaseFreeFighters[j]);

     if (BaseFreeHulls[j])
     {
     PutBaseHulls(planet, 1, 1);   /* One free ship in slot 1 */
     PutBaseHulls(planet, 2, 1);   /* One free ship in slot 2 */
     }

     if (BaseFreeEngines[j])
     {
     PutBaseEngines(planet, 1, 4); /* Four free StarDrive 1 engines */
     PutBaseEngines(planet, 3, 2); /* Two free StarDrive 3 engines */
     }

     if (BaseFreeBeams[j])
     {
     PutBaseBeams(planet, 2, 8);   /* Eight free X-Rays */
     }

     if (BaseFreeTorps[j])
     {
     PutBaseTubes(planet, 2, 3);   /* Three free Proton torpedo tubes */
     PutBaseTorps(planet, 2, 20);  /* 20 free Proton torpedoes */
     }
     } /* all BasesTheSame */
     else
     {
     PutBaseDefense(planet, 0);
     PutBaseFighters(planet, 0);
     }

     PutBaseOrder(planet, NoBaseMission);

     if (AdjustBasesTechs)
     {
     PutBaseTech(planet, ENGINE_TECH,
               ( (PlanetNatType(planet)==Ghipsoldal)? MAX_TECH : 1 ));
     PutBaseTech(planet, TORP_TECH,
               ( (PlanetNatType(planet)==Siliconoid)? MAX_TECH : 1 ));
     PutBaseTech(planet, HULL_TECH,
               ( (PlanetNatType(planet)==Humanoid)? MAX_TECH : 1   ));
     PutBaseTech(planet, BEAM_TECH,
               ( (PlanetNatType(planet)==Amphibian)? MAX_TECH : 1   ));
     }

     if (AllBasesTheSame)
     {
        PutBaseTech(planet, ENGINE_TECH, StartingEngineTech[j]);
        PutBaseTech(planet, HULL_TECH,   StartingHullTech[j]);
        PutBaseTech(planet, BEAM_TECH,   StartingBeamTech[j]);
        PutBaseTech(planet, TORP_TECH,   StartingTubeTech[j]);
     }

  }
 }
}

int PlanetDistance(Uns16 pID1, Uns16 pID2)
{
     int  t,out;
     int  x,y,x1,x2,y1,y2,dx,dy;

     if (!(IsPlanetExist(pID1) )) return 4000000;
     if (!(IsPlanetExist(pID2) )) return 4000000;

     x1= PlanetLocationX(pID1);
     x2= PlanetLocationX(pID2);

     y1= PlanetLocationY(pID1);
     y2= PlanetLocationY(pID2);

     x = abs(x1 - x2);
     y = abs(y1 - y2);

     dx= x;
     dy= y;

     if (AllowWraparoundMap) {
     t= UNI_DX-dx;
     if (x>t) x=t;

     t= UNI_DY-dy;
     if (y>t) y=t;

     }
     out  = x*x;
     out += y*y;

     return (out);
}

int          DistWrap2(int x1,int y1, int x2, int y2)
{
     int dx,dy,x,y,t,out;

     x = abs(x1 - x2);
     y = abs(y1 - y2);

     dx=x;
     dy=y;

     if (AllowWraparoundMap) {
     t= UNI_DX-dx;
     if (x>t) x=t;

     t= UNI_DY-dy;
     if (y>t) y=t;

     }
     out = x*x;
     out += y*y;

     return (out);
}

double min(double v1, double v2)
{
   return ( (v1 < v2) ? v1 : v2);
}

double max(double v1, double v2)
{
   return ( (v1 > v2) ? v1 : v2);
}

void ConOut(char *c)
{
#ifdef MSDOS
  cprintf("%s",c);
#endif
  return;
}


/*
**  Portable, public domain replacements for strupr() & strlwr() by Bob Stout
*/

char *strupr(char *string)
{
  char *s;

  if (string)
  {
        for (s = string; *s; ++s)
              *s = toupper(*s);
  }
  return string;
}


void PlanetStatistics(double table[])
{
     Uns32  Near=0;
     Uns32  Far=0;
     Uns16  Races=0;
     Uns16  i,j;
     Boolean NotHome[PLANET_NR+1];

     double near_home_aver = 0.0;
     double far_home_aver = 0.0;
     double near_aver = 0.0;
     double far_aver = 0.0;

     Uns32 NatCash = 0;
     Uns32 Cash = 0;
     double NatTax = 0.0;
     double cash_home_aver = 0.0;
     double cash_aver = 0.0;

     Uns32 NatMineT = 0;
     Uns32 NatMineD = 0;
     Uns32 NatMineM = 0;
     double MineRate = 0.0;
     double MineTurns = 0.0;
     double mine_t_home_aver = 0.0;
     double mine_d_home_aver = 0.0;
     double mine_m_home_aver = 0.0;
     double mine_t_aver = 0.0;
     double mine_d_aver = 0.0;
     double mine_m_aver = 0.0;

     double uni_n_aver = 0.0;
     double uni_t_aver = 0.0;
     double uni_d_aver = 0.0;
     double uni_m_aver = 0.0;

     double density_n_aver = 0.0;
     double density_t_aver = 0.0;
     double density_d_aver = 0.0;
     double density_m_aver = 0.0;

     Uns32  nat,natt,natg,pom,pom1,dd_;
     Uns32  NativesType[10],NativesGov[10],Climate[5];

     int Temp  = 0;
     Uns32 tt  = 0;
     double ttsd = 0.0, ttmn = 0.0;
     double  NatGovm = 0.0,NativePopulation = 0.0;
     Uns16  NatType = 0;

     if (!TestMode) Info("Computing statistics...");
     if (!TestMode) Info("* Near/far planets.");

     pom =NearSearchRadius*NearSearchRadius;
     pom1=FarSearchRadius*FarSearchRadius;
     for (i=1;i<=PLANET_NR;i++) NotHome[i]=True;
     for (i=1;i<=RACE_NR;i++) NotHome[Homeworlds[i]]=False;

     for (i=1;i<=RACE_NR;i++)
     {
      if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0))
      {
       for (j=1;j<=PLANET_NR;j++)
        if (XYisPlanet[j])
         if (Homeworlds[i]!=j)
          {
          dd_ = PlanetDist2(Homeworlds[i],j);
          if (dd_<=pom)  Near++;
          if (dd_<=pom1) Far++;
         }
        Races++;
       }
     }
    if (Races>0){
    near_home_aver=(double)Near/(double)Races;
    far_home_aver=(double)Far/(double)Races;
    }
    
    Near=0;
    Far=0;
    for (i=1;i<=PLANET_NR;i++)
   if (XYisPlanet[i])
     {
       if (NotHome[i])
       {
       for (j=1;j<=PLANET_NR;j++)
       if (XYisPlanet[j])
         if (NotHome[j])
         {
          dd_ = PlanetDist2(i,j);

          if ( dd_<=pom  ) Near++;
          if ( dd_<=pom1 ) Far++;
         }
       } /* if nothome */
     }
    if (PlanetsNumber-Races>0){
    near_aver=(double)Near/(double)(PlanetsNumber-Races);
    far_aver=(double)Far/(double)(PlanetsNumber-Races);
     }
     
    if (!TestMode) Info("* Natives number and government.");
    nat=0;
    for (j=1;j<10;j++) NativesType[j]=0;
    for (j=1;j<10;j++) NativesGov [j]=0;

    for (j=1;j<=PLANET_NR;j++)
    if (XYisPlanet[j])
      if ((pom=PlanetNatType(j))!=NoNatives)
      {
         NativesType[pom]++;
         NativesGov [PlanetNatGovm(j)]++;
         nat++;
      }
    natt = 0;
    for (i = 1; i < 10; i++)
         natt+= NativeTypeFrequencies[i];
    natg = 0;
    for (i = 1; i < 10; i++)
         natg += NativeGovFrequencies[i];

    if (!TestMode) Info("* Natives cash.");
      for (j=1;j<=PLANET_NR;j++)
        if (XYisPlanet[j])
          GlobalNatCash[j]=0;

       for (j=1;j<=PLANET_NR;j++)
        if (XYisPlanet[j])
          {
           if ((NatType=PlanetNatType(j))!=NoNatives)
           {
             NatGovm          = PlanetNatGovm(j);
             NativePopulation = PlanetNativePopulation(j);
             NatTax = (5.0 + NatGovm/2.0 - sqrt ( NativePopulation/10000.0/100.0))/0.85;
             if (NatType==Avian) NatTax+=10.0/0.85;
             Cash =(Uns32) ((NativePopulation/100.0*NatGovm*NatTax+2500.0)/5000.0);
             if (NatType==Insectoid) Cash*=2;
             if (NatType==Amorphous) Cash=0;
             GlobalNatCash[j]=(Uns32)(((float)Cash*100.0+50.0)/100.0);
           }
         }

     NatCash=0;
     pom=NativeCashSearchRadius*NativeCashSearchRadius;
     for (i=1;i<=RACE_NR;i++)
     {
      if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0))
       for (j=1;j<=PLANET_NR;j++)
        if (XYisPlanet[j])
         if (Homeworlds[i]!=j)
          if (PlanetNatType(j)!=NoNatives) 
           if (PlanetDist2(Homeworlds[i],j)<=pom)
            NatCash+=GlobalNatCash[j];
     }
     if (Races>0)
     cash_home_aver=(double)NatCash/(double)Races;

     NatCash=0;
     for (i=1;i<=PLANET_NR;i++)
     if (XYisPlanet[i])
     {
/* check if i is not home planet */
       if (NotHome[i])
       {
       for (j=1;j<=PLANET_NR;j++)
        if (XYisPlanet[j])
         if (NotHome[j])
          if (PlanetNatType(j)!=NoNatives)
           if ( PlanetDist2(i,j)<=pom )
             NatCash+=GlobalNatCash[j];

        } /* if nothome */
     }
    if (PlanetsNumber-Races>0)
    cash_aver=(double)NatCash/(double)(PlanetsNumber-Races);

    if (!TestMode) Info("* Minerals.");

    for (j=1;j<=PLANET_NR;j++)
    if (XYisPlanet[j])
       {
           NatType=PlanetNatType(j);
        /* Tritanium */
           MineRate = 200.0 * 100.0 * PlanetDensity(j,TRITANIUM)/100.0/100.0;
           if (NatType==Reptilian) MineRate*=2.0;
           MineTurns= (double)PlanetCore(j,TRITANIUM)/MineRate;
           if (MineTurns>MaxMineTurns) MineTurns=MaxMineTurns;
           GlobalMineT[j] = MineTurns*MineRate;

        /* Duranium */
           MineRate = 200.0 * 100.0 * PlanetDensity(j,DURANIUM)/100.0/100.0;
           if (NatType==Reptilian) MineRate*=2.0;
           MineTurns= (double)PlanetCore(j,DURANIUM)/MineRate;
           if (MineTurns>MaxMineTurns) MineTurns=MaxMineTurns;
           GlobalMineD[j] = MineTurns*MineRate;

        /* Molybdenium */
           MineRate = 200.0 * 100.0 * PlanetDensity(j,MOLYBDENUM)/100.0/100.0;
           if (NatType==Reptilian) MineRate*=2.0;
           MineTurns= (double)PlanetCore(j,MOLYBDENUM)/MineRate;
           if (MineTurns>MaxMineTurns) MineTurns=MaxMineTurns;
           GlobalMineM[j] = MineTurns*MineRate;
      }

  for (j=1;j<=PLANET_NR;j++)
  if (XYisPlanet[j])
  {
    GlobalMineT[j] = GlobalMineT[j]/MaxMineTurns;
    GlobalMineD[j] = GlobalMineD[j]/MaxMineTurns;
    GlobalMineM[j] = GlobalMineM[j]/MaxMineTurns;
  }

     NatMineT=0;
     NatMineD=0;
     NatMineM=0;
     pom=MineSearchRadius*MineSearchRadius;

     for (i=1;i<=RACE_NR;i++)
      if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0))
       for (j=1;j<=PLANET_NR;j++)
        if (XYisPlanet[j])
         if (Homeworlds[i]!=j)
          if (PlanetDist2(Homeworlds[i],j)<=pom)
           {
              NatMineT += GlobalMineT[j];
              NatMineD += GlobalMineD[j];
              NatMineM += GlobalMineM[j];
           }

     if (Races>0){
     mine_t_home_aver = (double)NatMineT/(double)Races;
     mine_d_home_aver = (double)NatMineD/(double)Races;
     mine_m_home_aver = (double)NatMineM/(double)Races;
    }
     NatMineT=0;
     NatMineD=0;
     NatMineM=0;

     for (i=1;i<=PLANET_NR;i++)
     if (XYisPlanet[i])
       if (NotHome[i])
       for (j=1;j<=PLANET_NR;j++)
       if (XYisPlanet[j])
        if (NotHome[j])
          if ( PlanetDist2(i,j)<=pom )
           {
              NatMineT += GlobalMineT[j];
              NatMineD += GlobalMineD[j];
              NatMineM += GlobalMineM[j];
          }

    if (PlanetsNumber-Races>0){
     mine_t_aver = (double)NatMineT/(double)(PlanetsNumber-Races);
     mine_d_aver = (double)NatMineD/(double)(PlanetsNumber-Races);
     mine_m_aver = (double)NatMineM/(double)(PlanetsNumber-Races);
     }
     uni_n_aver=0;
     uni_t_aver=0;
     uni_d_aver=0;
     uni_m_aver=0;

     density_n_aver=0;
     density_t_aver=0;
     density_d_aver=0;
     density_m_aver=0;

     for (i=1;i<=PLANET_NR;i++)
     if (XYisPlanet[i])
     {
       uni_n_aver+=PlanetCore(i,NEUTRONIUM);
       uni_t_aver+=PlanetCore(i,TRITANIUM);
       uni_d_aver+=PlanetCore(i,DURANIUM);
       uni_m_aver+=PlanetCore(i,MOLYBDENUM);

       density_n_aver+=PlanetDensity(i,NEUTRONIUM);
       density_t_aver+=PlanetDensity(i,TRITANIUM);
       density_d_aver+=PlanetDensity(i,DURANIUM);
       density_m_aver+=PlanetDensity(i,MOLYBDENUM);
     }

     if (PlanetsNumber>0){
       uni_t_aver/=PlanetsNumber;
       uni_n_aver/=PlanetsNumber;
       uni_d_aver/=PlanetsNumber;
       uni_m_aver/=PlanetsNumber;

       density_n_aver/=PlanetsNumber;
       density_t_aver/=PlanetsNumber;
       density_d_aver/=PlanetsNumber;
       density_m_aver/=PlanetsNumber;
     }
     
/* climate */
    if (!TestMode) Info("* Climate.");
    for (j=0;j<5;j++) Climate[j]=0;

    tt=0;
    for (i=1;i<=PLANET_NR;i++)
    if (XYisPlanet[i])
    if (IsPlanetExist(i))
    {
     Temp=PlanetTemp(i);

     tt += Temp;

     if ((Temp<= 100-61)&&(Temp>=100- 85)) Climate[3]++;
     else
     if ((Temp<= 100-15)&&(Temp>=100- 35)) Climate[1]++;
     else
     if ((Temp<= 100-36)&&(Temp>=100- 60)) Climate[2]++;
     else
     if ((Temp<= 100- 0)&&(Temp>=100- 14)) Climate[0]++;
     else
     if ((Temp<= 100-86)&&(Temp>=100-100)) Climate[4]++;
    }
    if (PlanetsNumber>0)
    ttmn=tt/(double)PlanetsNumber;

    /* temp std deviation */
    ttsd=0;
    for (i=1;i<=PLANET_NR;i++)
    if (XYisPlanet[i])
    if (IsPlanetExist(i))
    {
     Temp=PlanetTemp(i);
     ttsd+=(Temp-ttmn)*(Temp-ttmn);
    }
    if (PlanetsNumber>0)
    ttsd = sqrt( ttsd/ (double)PlanetsNumber);

    /* write to table */

    table[ 0] = near_home_aver;
    table[ 1] = near_aver;
    table[ 2] = far_home_aver;
    table[ 3] = far_aver;
    table[ 4] = cash_home_aver;
    table[ 5] = cash_aver;
    table[ 6] = mine_t_home_aver;
    table[ 7] = mine_t_aver;
    table[ 8] = mine_d_home_aver;
    table[ 9] = mine_d_aver;
    table[10] = mine_m_home_aver;
    table[11] = mine_m_aver;

    table[12] = uni_n_aver;
    table[13] = density_n_aver;
    table[14] = uni_t_aver;
    table[15] = density_t_aver;
    table[16] = uni_d_aver;
    table[17] = density_d_aver;
    table[18] = uni_m_aver;
    table[19] = density_m_aver;

    table[20] = nat;
    table[21] = natt;
    table[22] = natg;

    for (j=0;j<9;j++)  table[23+j] = NativesType[j+1];
    for (j=0;j<9;j++)  table[32+j] = NativesGov[j+1];
    for (j=0;j<5;j++)  table[41+j] = Climate[j];

    table[46] = ttmn;
    table[47] = ttsd;
    
}

void ShowPlanetStatistics(double table[])
{
     Uns16  j,i,RiG,RiG_,k;
     double expected_core;
     double expected_density,pcuf,dx1,dx2;
     double tmpa,tmpb;
     Uns32  area=0;

     char name1[6][10] = { "Near","Far ","Cash","Trit","Dur ","Moly" };
     char name2[4][10] = {               "Neut","Trit","Dur ","Moly" };

   /* display */

     RiG=0;
     RiG_=0;
     for (i=1;i<=RACE_NR;i++){
      if (RaceIsPlaying[i]) RiG++;
      if ((RaceIsPlaying[i])&&(OwnedPlanets[i]>0)) RiG_++;
     }
    Info("Displaying statistics...");

/* show HW stats */
    Info("");
    if (RiG_>0){
      Info("* Homeworlds statistics");
      Info("              Home      Uni   Home/Uni");
      for (j=0;j<6;j++)
        Info("%s    : %8.2f %8.2f %8.2f %%",name1[j],table[j*2],table[j*2+1],(table[j*2+1]!=0?table[j*2]/table[j*2+1]*100.0:0.0));
    }else{
      Info("* Universe statistics");
      Info("              Uni   ");
      for (j=0;j<6;j++)
        Info("%s    : %8.2f ",name1[j],table[j*2+1]);
    }
/* show universe mineral stats */
    Info("");
    Info("* Universe minerals");
    Info("           Universe              Expected            Uni/Exp");
    Info("           Core   Density        Core   Density      Core     Density");

    for (j=0;j<4;j++)
    {
    pcuf = (double)PlanetCoreUsualFrequency[j] /100.0;
    dx1  = (double)(PlanetCoreRangesUsual[j+4]    -PlanetCoreRangesUsual[j]);
    dx2  = (double)(PlanetCoreRangesAlternate[j+4]-PlanetCoreRangesAlternate[j]);
    expected_core=
            ((double)PlanetCoreRangesUsual[j]+dx1/2.0)*pcuf+
            ((double)PlanetCoreRangesAlternate[j]+dx2/2.0)*(1.0-pcuf);
    expected_density=(double)PlanetDensityRanges[0]+((double)PlanetDensityRanges[j+4]-(double)PlanetDensityRanges[j])/2.0;

    Info("%s : %8.2f %7.2f %%    %8.2f %7.2f %%    %6.2f %% %7.2f %%",name2[j],
          table[12+j*2],
          table[12+j*2+1],
          expected_core,
          expected_density,
          (expected_core!=0?table[12+j*2]/expected_core*100:0.0),
          (expected_density!=0?table[12+j*2+1]/expected_density*100:0.0));
    }

/* show natives stats */
    Info("");
    Info("* Natives races");
    Info("                 Universe  Expected    Uni/Exp");
    for (j=1;j<10;j++)
    {
       if (table[20]!=0)
          tmpa=(double)table[23-1+j]/(double)table[20]*100.0;
       else
          tmpa=0.0;
       if (table[21]!=0)
          tmpb=(double)NativeTypeFrequencies[j]/(double)table[21]*100.0;
       else
          tmpb=0.0;
       Info("%14s :  %5.2f %%   %5.2f %%  %8.2f %%",NativesString(j),
       tmpa,tmpb,(tmpb!=0?tmpa/tmpb*100:0.0));
    }

    Info("");
    Info("* Natives governments");
    Info("                 Universe  Expected    Uni/Exp");
    for (j=1;j<10;j++)
    {
       if (table[20]!=0)
          tmpa=(double)table[32-1+j]/(double)table[20]*100.0;
       else
          tmpa=0.0;
       if (table[22]!=0)
          tmpb=(double)NativeGovFrequencies[j]/(double)table[22]*100.0;
       else
          tmpb=0.0;
       Info("%14s :  %5.2f %%   %5.2f %%  %8.2f %%",NativesGovmString(j),
       tmpa,tmpb,(tmpb!=0?tmpa/tmpb*100:0.0));
    }

    Info("");
    Info("* Climate statistic");
    for (j=0;j<5;j++)
     Info ("%10s : %5.2f %%",ClimateString(j),(double)table[41+j]/(double)PlanetsNumber*100.0);
    Info("");
    Info("Mean temperature (std dev.): %5.1f (%.2f) F",table[46],table[47]);

    Info("");
    Info("* Universe surface");
    area = (WraparoundRectangle[2]-WraparoundRectangle[0])*(WraparoundRectangle[3]-WraparoundRectangle[1]);
    Info ("%10d square LY ( %5.2f %% of standard area).",area,area/4000000.0*100.0);
    Info ("%6.1f planets per 10^6 square LYs ( standard is %6.1f ).",(double)PlanetsNumber/(double)area*1000000.0,500.0/4.0);
    Info ("%6.2f races per 10^6 square LYs ( standard is %6.2f ).",(double)RiG/(double)area*1000000.0,11.0/4.0);
    Info("");

}


static void doShips(void)
{
  Uns16 i,j,r,ii;
  Uns16 SID;
  Uns16 hull;
  char  FC[4];
  char  ID[SHIP_NR+1];
  Uns16 ShipX[RACE_NR+1];
  Uns16 ShipY[RACE_NR+1];
  Uns16 MaxTrueHull[RACE_NR+1];
  Uns16 stry;

/*
In order to create ships with random id allocate all ship slots,
make ships with random id, finally delete all not used slots.
*/

for (i=1;i<=MaxShips;i++)
{
  CreateShip(Federation);
  ID[i]=0;
}

// find max true hull

for (i=1 ; i <=RACE_NR ; i++) {
  MaxTrueHull[i]=0;
  for (j=1 ; j <=RACEHULLS ; j++) {
     if (TrueHull(i,j) > 0) MaxTrueHull[i]++;
    }
 }
 
for (i=1 ; i <=RACE_NR ; i++)
  if (RaceIsPlaying[i])
   if (OwnedPlanets[i]>0)
  {
     ShipX[i]=PlanetLocationX( Homeworlds[i]);
     ShipY[i]=PlanetLocationY( Homeworlds[i]);
  }else
  {
      // Random position
      ShipX[i]=(Uns16)(WraparoundRectangle[0] +MyRandomRange(WraparoundRectangle[2]-WraparoundRectangle[0]-1)+1);
      ShipY[i]=(Uns16)(WraparoundRectangle[1] +MyRandomRange(WraparoundRectangle[3]-WraparoundRectangle[1]-1)+1);
  }


for (i=1 ; i <=RACE_NR ; i++)
{
if (RaceIsPlaying[i])
{
 for (r=0 ; r < (FreeShipsOnBases[i]?max(OwnedBases[i],1):1) ; r++)
  for (j=1 ; j < FreeShipsNumber[i]+1 ; j++)
{
  stry=0;
  SID=MyRandomRange(MaxShips)+1;
  while ((ID[SID]!=0)&&(stry<MAXSHIPTRY)) { SID=MyRandomRange(MaxShips)+1; stry++; }
  if (stry==MAXSHIPTRY)
  {
    Warning("Cannot create ship ! No ship slots free.");
    Warning("Race %d, ship #%d will not be created.",i,j+r*FreeShipsNumber[i]);
  }
  else  /* ship will be created */
  {
  ID[SID]=1;
/* owner */
   PutShipOwner(SID,i);
/* hull */
  if (FreeShipsAllTheSame)
    PutShipHull(SID,FreeShipsHull);
  else {
      ii =  (MapTruehullByPlayerRace?(j-1)%MaxTrueHull[PlayerRace[i]]+1:(j-1)%MaxTrueHull[i]+1);
      PutShipHull(SID,(MapTruehullByPlayerRace?TrueHull(PlayerRace[i],ii):TrueHull(i,ii)));
    }
  hull=ShipHull(SID);
/* engines */
  PutShipEngine(SID,FreeShipsEngines);
/* beams */
  if (HullBeamNumber(hull)>0)
  {
  PutShipBeamType(SID,FreeShipsBeams);
  PutShipBeamNumber(SID,HullBeamNumber(hull));
  }
/* torps */
  if (HullTubeNumber(hull)>0)
  {
  PutShipTorpType(SID,FreeShipsTubes);
  PutShipTubeNumber(SID,HullTubeNumber(hull));
  }
/* bays */
  if (HullBays(hull)>0)
  {
  PutShipBays(SID,HullBays(hull));
  }
/* free ammunition */
  if ((FreeShipsAmmo>0)&&((HullBays(hull)>0)||(HullTubeNumber(hull)>0)))
     PutShipAmmunition(SID,(FreeShipsAmmo<HullCargoCapacity(hull)?FreeShipsAmmo:HullCargoCapacity(hull)) );

/* warp */
  PutShipSpeed(SID,0);
/* location */
  if (OwnedPlanets[i]>0){
    PutShipLocationX(SID,PlanetLocationX( (r==0?Homeworlds[i]:Bases[i][r]) ));
    PutShipLocationY(SID,PlanetLocationY( (r==0?Homeworlds[i]:Bases[i][r]) ));
  }else{
    PutShipLocationX(SID,ShipX[i]);
    PutShipLocationY(SID,ShipY[i]);
  }
  
  PutShipRelWaypointX(SID,0);
  PutShipRelWaypointY(SID,0);

/* crew */
  PutShipCrew (SID,HullCrewComplement(hull));
/* name */
  PutShipName (SID,HullName(hull,NULL));
/* FC */
  sprintf(FC, "%03lu", MyRandomRange(1000));       /* random friendly code */
  PutShipFC(SID,FC);
  } /* ship wil be created */
} /* j-ships number and r-other bases */
}  /* race is playing */
} /* i-races */

/* delete not used ship slots*/
for (i=1;i<=MaxShips;i++)
if (ID[i]==0) DeleteShip(i);

}

static char *NativesString(Uns16 NatType)
{
   static char NatString[40];

   strcpy(NatString,"");

   if (NatType==NoNatives)  strcpy(NatString,"none");
   if (NatType==Humanoid)   strcpy(NatString,"Humanoid");
   if (NatType==Bovinoid)   strcpy(NatString,"Bovinoid");
   if (NatType==Reptilian)  strcpy(NatString,"Reptilian");
   if (NatType==Avian)      strcpy(NatString,"Avian");
   if (NatType==Amorphous)  strcpy(NatString,"Amorphous");
   if (NatType==Insectoid)  strcpy(NatString,"Insectoid");
   if (NatType==Amphibian)  strcpy(NatString,"Amphibian");
   if (NatType==Ghipsoldal) strcpy(NatString,"Ghipsoldal");
   if (NatType==Siliconoid) strcpy(NatString,"Siliconoid");

   return NatString;
}

static char *NativesGovmString(Uns16 NatGovm)
{
   static char NatString[40];

   strcpy(NatString,"");

   if (NatGovm==NoGovm)          strcpy(NatString,"NoGovm");
   if (NatGovm==Anarchy)         strcpy(NatString,"Anarchy");
   if (NatGovm==PreTribal)       strcpy(NatString,"PreTribal");
   if (NatGovm==EarlyTribal)     strcpy(NatString,"EarlyTribal");
   if (NatGovm==Tribal)          strcpy(NatString,"Tribal");
   if (NatGovm==Feudal)          strcpy(NatString,"Feudal");
   if (NatGovm==Monarchy)        strcpy(NatString,"Monarchy");
   if (NatGovm==Representative)  strcpy(NatString,"Representative");
   if (NatGovm==Participatory)   strcpy(NatString,"Participatory");
   if (NatGovm==Unity)           strcpy(NatString,"Unity");

   return NatString;
}

static char *ClimateString(Uns16 Climate)
{
   static char ClimString[40];

   strcpy(ClimString,"");

   if (Climate==0)          strcpy(ClimString,"Desert");
   if (Climate==1)          strcpy(ClimString,"Tropical");
   if (Climate==2)          strcpy(ClimString,"Warm");
   if (Climate==3)          strcpy(ClimString,"Cool");
   if (Climate==4)          strcpy(ClimString,"Arctic");

   return ClimString;
}


static void doGrey(void)
{
   FILE *f;
   Uns16 k,j,i,blind=0;
   struct ionstorm Ion[MAXIONSTORMS];
   Boolean IonCanBe;
   char blind2=0;

   f=OpenOutputFile("grey.hst",GAME_DIR_ONLY);

   /* Save ship crew experience, for 500 ships */
   for(i=0;i<500;i++)
     DOSWrite16(&blind,1,f);

   if (CreateIonStorms)
   {
  /* clear table */
   for (i=0;i<MAXIONSTORMS;i++)
   {
     Ion[i].x=0;
     Ion[i].y=0;
     Ion[i].r=0;
     Ion[i].v=0;
     Ion[i].head=0;
     Ion[i].mark=0;
   }

   /* generate ion storms */
   for (i=0;i<IonStormsNumber;i++)
   {
      j=MyRandomRange(50);
      while (Ion[j].mark==1) j=MyRandomRange(50);
      Ion[j].mark=1;
      IonCanBe=False;

      while (!IonCanBe)
      {
      Ion[j].x = (Uns16)(IonStormsCenterRange[0] +
                  MyRandomRange(IonStormsCenterRange[2]-IonStormsCenterRange[0]-1)+1);
      Ion[j].y = (Uns16)(IonStormsCenterRange[1] +
                  MyRandomRange(IonStormsCenterRange[3]-IonStormsCenterRange[1]-1)+1);
      IonCanBe=True;

      if (NoIonStormsNearHomeworlds)
      for (k=1;k<=RACE_NR;k++)
       {
        if ((RaceIsPlaying[k])&&(OwnedPlanets[k]>0))
         if (DistWrap2(Ion[j].x, Ion[j].y,
                      PlanetLocationX(Homeworlds[k]),
                      PlanetLocationY(Homeworlds[k]))<= MinIonStormsHomeDistance*MinIonStormsHomeDistance)
          IonCanBe=False;
       }
      } /* while IonCanBe */

      Ion[j].v = (Uns16)(IonStormsVoltageRange[0] +
                  MyRandomRange(IonStormsVoltageRange[1]-IonStormsVoltageRange[0]+1));
      Ion[j].r = (Uns16)(IonStormsRadiusRange[0] +
                  MyRandomRange(IonStormsRadiusRange[1]-IonStormsRadiusRange[0]+1));
      Ion[j].head = (Uns16) MyRandomRange(360);
   } /* for */

   /* save to grey.hst */
   for (i=0;i<MAXIONSTORMS;i++)
   {
     DOSWrite16(&Ion[i].x,1,f);
     DOSWrite16(&Ion[i].y,1,f);
     DOSWrite16(&Ion[i].r,1,f);
     DOSWrite16(&Ion[i].v,1,f);
     DOSWrite16(&Ion[i].head,1,f);

   /* 3 unused 16 bit values */
     DOSWrite16(&blind,1,f);
     DOSWrite16(&blind,1,f);
     DOSWrite16(&blind,1,f);
   }

   }
   else
   {
/* Empty ion storms */
     for(i=0;i<50*8;i++)
      DOSWrite16(&blind,1,f);
   }

   /* PBP */
   for(i=0;i<11;i++)
     DOSWrite16(&blind,1,f);

   /* THost aliances */
   for(i=0;i<11;i++)
     DOSWrite16(&blind,1,f);

   /* Host999 crew experience, ships ID 501 - 999*/
   for(i=0;i<499;i++)
     DOSWrite16(&blind,1,f);

   /* 5 bytes of unknown interpretation */
   for(i=0;i<5;i++) fwrite(&blind2,1,1,f);

   /* More THost aliances */
   for(i=0;i<11;i++)
     DOSWrite16(&blind,1,f);

   if (f!=NULL) fclose(f);
   return;
}

void ShowPlayersPIDs(void)
{
  Uns16 i,j,Bk,Pk;
  Uns16 Bbuf[MAXHOMEPLANETS+5]; /* +5 is for safe */
  Uns16 Pbuf[MAXHOMEPLANETS+5];
  char  buf[1000];
  char  buf1[1000];

  Info("Players HomeWorlds and HomePlanets IDs :");

for (i=1 ; i <=RACE_NR ; i++)
 {
 if (RaceIsPlaying[i])
   {
/* scan for bases and planets */
    Bk=0;
    Pk=0;
/* first scan for homeworlds */
    for (j=1 ; j <= PLANET_NR ; j++)
    if ((XYisPlanet[j])&&(IsPlanetExist(j)))
    {
      if (Homeworlds[i]==j)
      {
      if ((PlanetOwner(j)==i)&&( IsBaseExist(j))) { Bbuf[Bk]=j; Bk++; }
      if ((PlanetOwner(j)==i)&&(!IsBaseExist(j))) { Pbuf[Pk]=j; Pk++; }
      }
    }

    for (j=1 ; j <= PLANET_NR ; j++)
    if ((XYisPlanet[j])&&(IsPlanetExist(j)))
    {
      if (Homeworlds[i]!=j)
      {
      if ((PlanetOwner(j)==i)&&( IsBaseExist(j))) { Bbuf[Bk]=j; Bk++; }
      if ((PlanetOwner(j)==i)&&(!IsBaseExist(j))) { Pbuf[Pk]=j; Pk++; }
      }
    }

    strcpy(buf,"");
    for (j=0;j<Bk;j++) {
        sprintf(buf1,"%3dB",Bbuf[j]);
        if (Homeworlds[i]==Bbuf[j]) strcat(buf1,"H");
        if ((j<Bk-1)||(Pk>0))       strcat(buf1,", ");
        strcat(buf,buf1); }


    for (j=0;j<Pk;j++) {
        sprintf(buf1,"%3d",Pbuf[j]);
        if (Homeworlds[i]==Pbuf[j]) strcat(buf1,"H");
        if (j<Pk-1)       strcat(buf1,", ");
        strcat(buf,buf1); }

    Info("Race %2d : %s",i,buf);
   } /* race is playing */
 }/* i==12 */
}

void ShowPlayersInfo(void)
{
  Uns16 i,j,Bk,Pk,Sk,fs;
  Uns16 TB=0,TS=0,TP=0;

  Info("Players planets, bases and ships numbers:");
  Info("       %12s%12s%12s","Planets","Bases","Ships");

for (i=1 ; i <=RACE_NR ; i++)
 {
 if (RaceIsPlaying[i])
   {
/* scan for bases and planets */
    Bk=0;
    Pk=0;
    for (j=1 ; j <= PLANET_NR ; j++)
    if ((XYisPlanet[j])&&(IsPlanetExist(j)))
    {
      if ((PlanetOwner(j)==i)&&( IsBaseExist(j))) { Bk++; }
      if (PlanetOwner(j)==i)                      { Pk++; }
    }

/* scan for ships */
    Sk=0;
    for (j=1 ; j <= SHIP_NR ; j++)
    if (IsShipExist(j))
      if (ShipOwner(j)==i)   { Sk++; }

    if (FreeShips) fs=FreeShipsNumber[i]*(FreeShipsOnBases[i]?max(OwnedBases[i],1):1);
    else fs=0;
    Info("Race %2d : %3d of %3d   %3d of %3d   %3d of %3d",i,
                                 Pk,OwnedPlanets[i],
                                 Bk,OwnedBases[i],
                                 Sk,fs);
    TB += Bk;
    TP += Pk;
    TS += Sk;
   } /* race is playing */
 }/* i==12 */

 Info("Total player planets : %d",TP);
 Info("Total player bases   : %d",TB);
 Info("Total player ships   : %d",TS);
}



Uns32 MaxNativesOnPlanet(Uns16 NativesType,Uns16 Temp)
{
  float nat;

  if (ClimateLimitsPopulation)
  {

  if ((NativesType==Siliconoid)&&(CrystalsPreferDeserts))
  {
     nat = Temp*100000.0 ;
  }
  else /* for no siliconoid or Crystals does not prefer deserts */
   nat = sin( 3.14159*Temp/100.0)*15600000.0 ;

  }
  else
   nat = 15600000.0; /* not depending on temperature */

/*  if (nat<100.0) nat=100.0; */

  return (Uns32)nat;
}

Uns32 GetOutsideWrapX(void)
{
   Uns32 X;

   X = (Uns32)(WraparoundRectangle[0] * 0.5 );
   if (MyRandomRange(100)>50)
      return X;
   else
      return (Uns32)(WraparoundRectangle[2] + X );
}

Uns32 GetOutsideWrapY(void)
{
   Uns32 Y;

   Y = (Uns32)(WraparoundRectangle[1] * 0.5 );
   if (MyRandomRange(100)>50)
      return Y;
   else
      return (Uns32)(WraparoundRectangle[3] + Y );
}

void CountPlanets(double table[])
{
  Boolean temp_pl[PLANET_NR+1];
  int i,j,MineT,MineD,MineM,dec_mine;
  int Near, Far, Mine, Border, Cash, All;
  Uns32 pom,temp;

  Near   = PlanetsNumber;
  Far    = PlanetsNumber;
  Mine   = PlanetsNumber;
  Border = PlanetsNumber;
  Cash   = PlanetsNumber;

  /* total */
  for(i=1;i<=PLANET_NR;i++) temp_pl[i] = True;

  /* near & far */
  if (NearFarPlanetCheck)
  {
     for (i=1;i<=PLANET_NR;i++)
        if (XYisPlanet[i])
         {
            if ((GlobalNear[i]>NearPlanetsNo[1])||
                (GlobalNear[i]<NearPlanetsNo[0])) { temp_pl[i]=False; Near--; }
            if ((GlobalFar[i] > FarPlanetsNo[1])||
                (GlobalFar[i] < FarPlanetsNo[0])) { temp_pl[i]=False; Far--; }
         }
  }

  /* border */
  if ( ! AllowWraparoundMap)
  {
    for (i = 1; i <= PLANET_NR; i++)
     if (XYisPlanet[i])
     if ((PlanetLocationX(i)<HomeworldsRange[0])||
         (PlanetLocationX(i)>HomeworldsRange[2])||
         (PlanetLocationY(i)<HomeworldsRange[1])||
         (PlanetLocationY(i)>HomeworldsRange[3]))  { temp_pl[i]=False; Border--; }
  }

  /* cash */
  if (NativeCashCheck)
  {
  pom = NativeCashSearchRadius*NativeCashSearchRadius;
  for (i=1;i<=PLANET_NR;i++)
  if (XYisPlanet[i])
    {
     temp=0;
     for (j=1;j<=PLANET_NR;j++)
      if (XYisPlanet[j])
       if (i!=j)
        if (PlanetDist2(i,j)<=pom)
           temp+=GlobalNatCash[j];
     if ((temp>NativeCash[1])||(temp<NativeCash[0])) { temp_pl[i]=False; Cash--; }
    }
  }
   /* mine */
  if (MineCheck)
  {
  pom = MineSearchRadius*MineSearchRadius;
  for (i=1;i<=PLANET_NR;i++)
  if (XYisPlanet[i])
      {
       MineT=0;
       MineD=0;
       MineM=0;

       for (j=1;j<=PLANET_NR;j++)
       if (XYisPlanet[j])
        if (i!=j)
         if (PlanetDist2(i,j)<=pom)
        {
          MineT+=GlobalMineT[j];
          MineD+=GlobalMineD[j];
          MineM+=GlobalMineM[j];
        }

       dec_mine = False;
       if ((MineT>MineTritanium[1]  )||
           (MineT<MineTritanium[0]  ))    { temp_pl[i]=False; dec_mine = True; }
       else
       if ((MineD>MineDuranium[1]   )||
           (MineD<MineDuranium[0]   ))    { temp_pl[i]=False; dec_mine = True; }
       else
       if ((MineM>MineMolybdenium[1])||
           (MineM<MineMolybdenium[0]))    { temp_pl[i]=False; dec_mine = True; }

       if (dec_mine) Mine--;
      }
  }
  /* total */
  All=0;
  for(i=1;i<=PLANET_NR;i++) if (temp_pl[i]) All++;

  table[0] = Border;
  table[1] = Near;
  table[2] = Far;
  table[3] = Cash;
  table[4] = Mine;
  table[5] = All;
}

void ShowCountPlanets(double table[])
{
  /* show results */
  if ((MineCheck)||(NearFarPlanetCheck)||
      (NativeCashCheck)||(!AllowWraparoundMap))
  {
  Info("Statistic on fulfilling Homeworlds checks.");
  Info("Condition Number Number/Total");
  }

  if (!AllowWraparoundMap)
    Info("%9s %6.2f     %6.2f %%","border",table[0],table[0]/(double)PlanetsNumber*100.0);
  if (NearFarPlanetCheck)
  {
    Info("%9s %6.2f     %6.2f %%","near",table[1],table[1]/(double)PlanetsNumber*100.0);
    Info("%9s %6.2f     %6.2f %%","far",table[2],table[2]/(double)PlanetsNumber*100.0);
  }
  if (NativeCashCheck)
    Info("%9s %6.2f     %6.2f %%","cash",table[3],table[3]/(double)PlanetsNumber*100.0);
  if (MineCheck)
    Info("%9s %6.2f     %6.2f %%","mine",table[4],table[4]/(double)PlanetsNumber*100.0);

  if ((MineCheck)||(NearFarPlanetCheck)||
      (NativeCashCheck)||(!AllowWraparoundMap))
  {
  Info("");
  Info("%9s %6.2f     %6.2f %%","ALL",table[5],table[5]/(double)PlanetsNumber*100.0);
  Info("");
  }
}

/************************************************************************
 This random number generator originally appeared in "Toward a Universal
 Random Number Generator" by George Marsaglia and Arif Zaman.
 Florida State University Report: FSU-SCRI-87-50 (1987)

 It was later modified by F. James and published in "A Review of Pseudo-
 random Number Generators"

 Converted from FORTRAN to C by Phil Linttell, James F. Hickling
 Management Consultants Ltd, Aug. 14, 1989.

 THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE.
       (However, a newly discovered technique can yield
         a period of 10^600. But that is still in the development stage.)

 It passes ALL of the tests for random number generators and has a period
   of 2^144, is completely portable (gives bit identical results on all
   machines with at least 24-bit mantissas in the floating point
   representation).

 The algorithm is a combination of a Fibonacci sequence (with lags of 97
   and 33, and operation "subtraction plus one, modulo one") and an
   "arithmetic sequence" (using subtraction).

************************************************************************/
double u[97], c, cd, cm;
int i97, j97, test=False;
/************************************************************************
 This is the initialization routine for the random number generator RANMAR()
 NOTE: The seed variables can have values between:    0 <= IJ <= 31328
                                                      0 <= KL <= 30081
 The random number sequences created by these two seeds are of sufficient
 length to complete an entire calculation with. For example, if several
 different groups are working on different parts of the same calculation,
 each group could be assigned its own IJ seed. This would leave each group
 with 30000 choices for the second seed. That is to say, this random
 number generator can create 900 million different subsequences -- with
 each subsequence having a length of approximately 10^30.

 Use IJ = 1802 & KL = 9373 to test the random number generator. The
 subroutine RANMAR should be used to generate 20000 random numbers.
 Then display the next six random numbers generated multiplied by 4096*4096
 If the random number generator is working properly, the random numbers
 should be:
           6533892.0  14220222.0   7275067.0
           6172232.0   8354498.0  10633180.0
************************************************************************/
int rmarin(int ij, int kl)
{

        double s, t;
        int i, j, k, l, m;
        int ii, jj;

        /* Change FALSE to TRUE in the next statement to test the
           random routine.*/

        test = True;

        if ( ( ij < 0 || ij > 31328 ) ||
                ( kl < 0 || kl > 30081 ) )
        {
                printf ("RMARIN: The first random number seed must have a "
                        "value between 0 and 31328\n");
                printf ("        The second random number seed must have a "
                        "value between 0 and 30081");
                return 1;
        }

        i = (int)fmod(ij/177.0, 177.0) + 2;
        j = (int)fmod(ij      , 177.0) + 2;
        k = (int)fmod(kl/169.0, 178.0) + 1;
        l = (int)fmod(kl      , 169.0);

        for ( ii=0; ii<=96; ii++ )
        {
                s = (double)0.0;
                t = (double)0.5;
                for ( jj=0; jj<=23; jj++ )
                {
                        m = (int)fmod( fmod(i*j,179.0)*k , 179.0 );
                        i = j;
                        j = k;
                        k = m;
                        l = (int)fmod( 53.0*l+1.0 , 169.0 );
                        if ( fmod(l*m,64.0) >= 32)
                                s = s + t;
                        t = (double)(0.5 * t);
                }
                u[ii] = s;
        }

        c  = (double)(  362436.0 / 16777216.0);
        cd = (double)( 7654321.0 / 16777216.0);
        cm = (double)(16777213.0 / 16777216.0);

        i97 = 96;
        j97 = 32;

        test = True;

        return 0;
}

double ranmar(void)
{
        double uni;

        if ( !test )
        {
                printf ("RANMAR: Call the initialization routine (RMARIN) "
                        "before calling RANMAR.\n");
                return 1;
        }

        uni = u[i97] - u[j97];
        if ( uni < 0.0F )
                uni = uni + 1.0;
        u[i97] = uni;
        i97--;
        if ( i97 < 0 )
                i97 = 96;
        j97--;
        if ( j97 < 0 )
                j97 = 96;
        c = c - cd;
        if ( c < 0.0F )
                c = c + cm;
        uni = uni - c;
        if ( uni < 0.0F )
                uni = uni + 1.0;

        return uni;
}

/* I use the following procedure in TC to generate seeds:

  The sow() procedure calculates two seeds for use with the random number
  generator from the system clock.  I decided how to do this myself, and
  I am sure that there must be better ways to select seeds; hopefully,
  however, this is good enough.  The first seed is calculated from the values
  for second, minute, hour, and year-day; weighted with the second most
  significant and year-day least significant.  The second seed weights the
  values in reverse.
*/

void sow( seed1, seed2 )
int *seed1, *seed2;
{
        struct tm *tm_now;
        double s_sig, s_insig, maxs_sig, maxs_insig;
        time_t secs_now;
        int s, m, h, d, s1, s2;

        time(&secs_now);
        tm_now = localtime(&secs_now);

        s = tm_now->tm_sec + 1;
        m = tm_now->tm_min + 1;
        h = tm_now->tm_hour + 1;
        d = tm_now->tm_yday + 1;

        maxs_sig   = (double)(60.0 + 60.0/60.0 + 24.0/60.0/60.0 +
              366.0/24.0/60.0/60.0);
        maxs_insig = (double)(60.0 + 60.0*60.0 + 24.0*60.0*60.0 +
              366.0*24.0*60.0*60.0);

        s_sig      = (double)(s + m/60.0 + h/60.0/60.0 + d/24.0/60.0/60.0);
        s_insig    = (double)(s + m*60.0 + h*60.0*60.0 + d*24.0*60.0*60.0);

        s1 = (int)(s_sig   / maxs_sig   * 31328.0);
        s2 = (int)(s_insig / maxs_insig * 30081.0);

        *seed1 = s1;
        *seed2 = s2;
}
/*
   End of code from Snip97 archive.
   Small modificated to suit Amaster needs by Piotr Winiarczyk.
*/

/* This are wrapper functions for random generator */

void MySetRandomSeed(long seed)
{
  rmarin(seed % 31328 ,seed / 31328 );
}

long MyGetRandomSeed(void)
{
  int i,j;

  sow(&i,&j);
  return i + j * 31328;
}

long MyRandomRange(long Range)
{
  /* random seed was not set */
  if (!test) MySetRandomSeed(MyGetRandomSeed());

  return (long)(ranmar()*(double)Range);
}

void ShowHomeInfo(void)
{
  int   k,j,i;
  Uns32 pom;
  char  tmp1[200],tmp2[200],tmp3[200],tmp4[200];
  Uns32 NatCash[RACE_NR+1];
  Uns32 NatMineT[RACE_NR+1];
  Uns32 NatMineD[RACE_NR+1];
  Uns32 NatMineM[RACE_NR+1];

  if (NativeCashCheck)
  {
  pom=NativeCashSearchRadius*NativeCashSearchRadius;
  for (k=1;k<=RACE_NR;k++)
   if ((RaceIsPlaying[k])&&(OwnedPlanets[k]>0))
       {
        i=Homeworlds[k];
        NatCash[k]=0;
        for (j=1;j<=PLANET_NR;j++)
        if (XYisPlanet[j])
         if (i!=j)
          if (PlanetDist2(i,j)<=pom)
            NatCash[k]+=GlobalNatCash[j];
       }
  }
  /* HW compute statistic */
  if (MineCheck)
  {
  pom= MineSearchRadius*MineSearchRadius;
  for (k=1;k<=RACE_NR;k++)
   if ((RaceIsPlaying[k])&&(OwnedPlanets[k]>0))
      {
       i=Homeworlds[k];

       NatMineT[k]=0;
       NatMineD[k]=0;
       NatMineM[k]=0;

       for (j=1;j<=PLANET_NR;j++)
       if (XYisPlanet[j])
        if (i!=j)
         if (PlanetDist2(i,j)<=pom)
        {
          NatMineT[k]+=GlobalMineT[j];
          NatMineD[k]+=GlobalMineD[j];
          NatMineM[k]+=GlobalMineM[j];
        }
      }
  }
  for(i=1;i<=RACE_NR;i++)
   if (RaceIsPlaying[i])
      if (OwnedPlanets[i]>0)
      {
        sprintf(tmp1,"%13s ",RaceNameAdjective(i,NULL));
        if (NearFarPlanetCheck) sprintf(tmp2,"Planets near %2d, far %2d ",GlobalNear[Homeworlds[i]],GlobalFar[Homeworlds[i]]);
        else                    strcpy(tmp2,"");
        if (NativeCashCheck)    sprintf(tmp3,"Cash : %6ld ",NatCash[i]);
        else                    strcpy(tmp3,"");
        if (MineCheck)          sprintf(tmp4,"Mine T:%4ld D:%4ld M:%4ld",
                                            NatMineT[i],
                                            NatMineD[i],
                                            NatMineM[i]);
        else                    strcpy(tmp4,"");
        strcat(tmp1,tmp2);
        strcat(tmp1,tmp3);
        strcat(tmp1,tmp4);
        Info(tmp1);
      }
      else
      {
        sprintf(tmp1,"%13s ",RaceNameAdjective(i,NULL));
        strcat(tmp1,"No Homeword");
        Info(tmp1);
      }
}

/* Do refdata.hst file , a victory condition for THost */
static void doRefData(void)
{
   FILE *f;
   Uns16 k,i,blind=0;

   f=OpenOutputFile("refdata.hst",GAME_DIR_ONLY);

   /* 0 - no scenario */
   DOSWrite16(&blind,1,f);
   /* 2 - Homeworlds picked manually */
   i=2;
   DOSWrite16(&i,1,f);
   /* 0 - ? */
   DOSWrite16(&blind,1,f);
   /* Homeworlds IDs */
  for (k=1;k<=RACE_NR;k++)
   if ((RaceIsPlaying[k])&&(OwnedPlanets[k]>0))
       {
        i=Homeworlds[k];
        DOSWrite16(&i,1,f);
       }
   else
        DOSWrite16(&blind,1,f);
   /* fill with 0's */
    for (k=1;k<=69;k++)
        DOSWrite16(&blind,1,f);

   if (f!=NULL) fclose(f);
   return;
}

void CheckForErrorsInConfig(void)
{
  Uns16 k;
  char  kk;
  
  /* Checking for errors in config file. */

  if ((UsePGMMaskFile)&&(CreateMap)&&(FixMapSums)&&(CreateXYMap)) {
    Warning("Using map mask file and fixing map checksums is not recomended.");
    Warning("Consider invoking AMASTER with -u option.");
  }

  if ((ProvideHomeworlds)&&(CreateMap)&&(CreateXYMap)) {
    Warning("Setting ProvideHomewords=Yes and CreateMap=Yes is not recomended.");
    Warning("Consider changing one of these options to No.");
  }

 if (ProvideHomeworlds)  {
  kk=0;
  for (k=1;k<=RACE_NR;k++)
   if ((RaceIsPlaying[k])&&(OwnedPlanets[k]==0))
      kk=1;

  if (kk==1)  {
    Warning("Setting ProvideHomewords=Yes and OwnedPlanets=0 is not recomended.");
    Warning("Consider changing one of these options.");
  }
  }

 for (k=1 ; k <=RACE_NR ; k++)
 if (RaceIsPlaying[k]) {
  /* one cannot have more bases than planets */
  if (OwnedBases[k]>OwnedPlanets[k])  {
    OwnedBases[k]=OwnedPlanets[k];
    Warning("Number of OwnedBases cannot be bigger than number of OwnedPlanets.");
    Warning("Number of OwnedBases adjusted for race : %d",k);
  }
 }
  return;
}

void TryReadPConfig(void)
{
    FILE *f;
    int i;
    
 // Check if pconfig.src is in root dir    
    f=OpenInputFile("pconfig.src",GAME_DIR_ONLY|NO_MISSING_ERROR);
    if (f == NULL) return; // no file
    fclose(f);

    if (!Read_HConfig_File()) { Warning("Check pconfig.src file."); return; }
    Info("Reading file : %s, section : %%PCONFIG","pconfig.src"); // little cheat :-)
    if (PHost4Support)
      MaxShips = gPconfigInfo->NumShips;
    else
      MaxShips = PHOST3_SHIP_NR;
  
    /* Set same params that can be both in pconfig.src and amaster.src */
    
    for(i=1;i<=RACE_NR;i++)
      PlayerRace[i]          = gPconfigInfo->PlayerRace[i];            // 120
    config[120].read=True;
    MapTruehullByPlayerRace  = gPconfigInfo->MapTruehullByPlayerRace;  // 121
    config[121].read=True;
    AllowWraparoundMap       = gPconfigInfo->AllowWraparoundMap;       //  33
    config[ 33].read=True;
    for(i=0;i<4;i++)
      WraparoundRectangle[i] = gPconfigInfo->WraparoundRectangle[i];   //  98
    config[ 98].read=True;
    CrystalsPreferDeserts    = gPconfigInfo->CrystalsLikeDesert;       //  36
    config[ 36].read=True;
    CrystalSinTempBehavior   = gPconfigInfo->CrystalSinTempBehavior;   // 122
    config[122].read=True;    
    ClimateLimitsPopulation  = gPconfigInfo->ClimateLimitsPopulation;  // 123
    config[123].read=True;
    MaxColTempSlope          = gPconfigInfo->MaxColTempSlope;          // 132
    config[132].read=True;    
  
  return;
}

unsigned char *LoadPGMFile(char *fileName){
        
   FILE *f;
   char buf[100];
   int type=0;
   int a,b,c,ile,exp=2;
   int x,y,d,i,j,cc;
   unsigned char *pic;
   unsigned char aa;

   f=OpenInputFile(fileName,GAME_DIR_ONLY);
   
   fgets(buf,80,f);
   if (strstr(buf,"P5")) type=1;
   if (strstr(buf,"P2")) type=2;
   if (type==0) { ErrorExit("It is not PGM file : %s",fileName); }
   fgets(buf,80,f);
   if (strstr(buf,"#")) ((char *)strstr(buf,"#"))[0]=0;
   ile = sscanf(buf,"%d %d",&a,&b);
   if (ile==exp) { x=a; y=b; exp=1; }
   fgets(buf,80,f);
   if (strstr(buf,"#")) ((char *)strstr(buf,"#"))[0]=0;
   ile = sscanf(buf,"%d %d",&a,&b);
   if (ile==exp) { x= a; y=b; exp=1;}
   if (ile==exp) { d= a; exp=0; }

   if (exp!=0){
      fgets(buf,80,f);
      if (strstr(buf,"#")) ((char *)strstr(buf,"#"))[0]=0;
      ile = sscanf(buf,"%d %d",&a,&b);
      if (ile==exp) { d= a; exp=0;}
   }
   pic=(unsigned char *)malloc(x*y);
   if (type==1) fread(pic,x*y,1,f);
   if (type==2) {
      j=0;
      for (i=0;i<x*y;i++) {
          while(((cc=fgetc(f)) != EOF)&&(cc!=0x20)&&(cc!=0x0d)&&(cc!=0x0a)){
            buf[j]=(unsigned char)cc; j++;}
          buf[j]=0x00;
          ile = sscanf(buf,"%d",&a);
          if (ile!=1) { 
                ErrorExit("Cannot load PGM file : %s",fileName); 
                }
          pic[i]=(unsigned char)a;
          while(((cc=fgetc(f)) != EOF)&&((cc==0x20)||(cc==0x0a)||(cc==0x0d))){}
          j=0; buf[j]=(unsigned char)cc; j++;
      }
   }
   fclose(f);
   PGMFileX = x;
   PGMFileY = y;
   PGMFileD = d;
   return pic;
}
